class ExperimentSettings(Singleton): global_settings = {} timeline = Timeline('TEST_STOCK') subscribers = {} def __init__(self): pass def set_field(self, tag, value, notify_subscribers=True): self.global_settings[tag] = value if re.match(get_matchstring_for_subtag(2, 'Well'), tag): self.update_timeline(tag) if notify_subscribers: self.notify_subscribers(tag) print 'SET FIELD: %s = %s' % (tag, value) def get_field(self, tag, default=None): return self.global_settings.get(tag, default) def remove_field(self, tag, notify_subscribers=True): '''completely removes the specified tag from the metadata (if it exists) ''' #if self.get_field(tag) is not None: self.global_settings.pop(tag) if re.match(get_matchstring_for_subtag(2, 'Well'), tag): self.update_timeline(tag) if notify_subscribers: self.notify_subscribers(tag) print 'DEL FIELD: %s' % (tag) def get_action_tags(self): '''returns all existing TEMPORAL tags as list''' return [ tag for tag in self.global_settings if tag.split('|')[0] in ('CellTransfer', 'Perturbation', 'Labeling', 'AddProcess', 'DataAcquis') ] def get_field_instances(self, tag_prefix): '''returns a list of unique instance ids for each tag beginning with tag_prefix''' ids = set([ get_tag_instance(tag) for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_attribute_list(self, tag_prefix): '''returns a list of attributes name for each tag beginning with tag_prefix''' ids = set([ get_tag_attribute(tag) for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_attribute_dict(self, protocol): '''returns a dict mapping attribute names to their values for a given protocol. eg: get_attribute_dict('CellTransfer|Seed|1') --> {'SeedingDensity': 12, 'MediumUsed': 'agar', 'MediumAddatives': 'None', 'Trypsinization': True} ''' d = {} for tag in self.get_matching_tags('|*|'.join(protocol.rsplit('|', 1))): if (get_tag_attribute(tag) not in ('Wells', 'EventTimepoint', 'Images', 'OriginWells')): d[get_tag_attribute(tag)] = self.global_settings[tag] return d def get_eventtype_list(self, tag_prefix): '''returns a list of attributes name for each tag beginning with tag_prefix''' ids = set([ tag.split('|')[1] for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_eventclass_list(self, tag_prefix): '''returns a list of event class name for each tag beginning with tag_prefix''' ids = set([ tag.split('|')[0] for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_field_tags(self, tag_prefix=None, instance=None): '''returns a list of all tags beginning with tag_prefix. If instance is passed in, only tags of the given instance will be returned''' tags = [] for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instance is None or get_tag_instance(tag) == instance)): tags += [tag] return tags def get_matching_tags(self, matchstring): '''returns a list of all tags matching matchstring matchstring -- a string that matches the tags you want eg: CellTransfer|* ''' tags = [] for tag in self.global_settings: match = True for m, subtag in map(None, matchstring.split('|'), tag.split('|')): if m != subtag and m not in ('*', None): match = False break if match: tags += [tag] return tags def get_protocol_instances(self, prefix): '''returns a list of protocol instance names for tags matching the given prefix. ''' return list( set([get_tag_instance(tag) for tag in self.get_field_tags(prefix)])) def get_new_protocol_id(self, prefix): '''returns an id string that hasn't been used for the given tag prefix prefix -- eg: CellTransfer|Seed ''' instances = self.get_protocol_instances(prefix) for i in xrange(1, 100000): if str(i) not in instances: return str(i) def clear(self): self.global_settings = {} PlateDesign.clear() # # TODO: # self.timeline = Timeline('TEST_STOCK') for matchstring, callbacks in self.subscribers.items(): for callback in callbacks: callback(None) def get_timeline(self): return self.timeline def update_timeline(self, welltag): '''Updates the experiment metadata timeline event associated with the action and wells in welltag (eg: 'ExpNum|AddProcess|Spin|Wells|1|1') ''' platewell_ids = self.get_field(welltag, []) if platewell_ids == []: self.timeline.delete_event(welltag) else: event = self.timeline.get_event(welltag) if event is not None: event.set_well_ids(platewell_ids) else: self.timeline.add_event(welltag, platewell_ids) def save_to_file(self, file): f = open(file, 'w') for field, value in sorted(self.global_settings.items()): f.write('%s = %s\n' % (field, repr(value))) f.close() def load_from_file(self, file): # Populate the tag structure self.clear() f = open(file, 'r') for line in f: tag, value = line.split('=') tag = tag.strip() self.set_field(tag, eval(value), notify_subscribers=False) f.close() # Populate PlateDesign PlateDesign.clear() for vessel_type in ('Plate', 'Flask', 'Dish', 'Coverslip'): prefix = 'ExptVessel|%s' % (vessel_type) for inst in self.get_field_instances(prefix): d = self.get_attribute_dict(prefix + '|' + inst) shape = d.get('Design', None) if shape is None: shape = (1, 1) group = d.get('GroupName', None) PlateDesign.add_plate(vessel_type, inst, shape, group) # Update everything for tag in self.global_settings: self.notify_subscribers(tag) # Update the bench time-slider # TODO: this is crappy try: import wx bench = wx.GetApp().get_bench() bench.set_time_interval(0, self.get_timeline().get_max_timepoint()) except: return def add_subscriber(self, callback, match_string): '''callback -- the function to be called match_string -- a regular expression string matching the tags you want to be notified of changes to ''' self.subscribers[match_string] = self.subscribers.get( match_string, []) + [callback] def remove_subscriber(self, callback): '''unsubscribe the given callback function. This MUST be called before a callback function is deleted. ''' for k, v in self.subscribers: if v == callback: self.subscribers.pop(k) def notify_subscribers(self, tag): for matchstring, callbacks in self.subscribers.items(): if re.match(matchstring, tag): for callback in callbacks: callback(tag)
class ExperimentSettings(Singleton): global_settings = {} timeline = Timeline('TEST_STOCK') subscribers = {} def __init__(self): pass def set_field(self, tag, value, notify_subscribers=True): self.global_settings[tag] = value if re.match(get_matchstring_for_subtag(2, 'Well'), tag): self.update_timeline(tag) if notify_subscribers: self.notify_subscribers(tag) print 'SET FIELD: %s = %s'%(tag, value) def get_field(self, tag, default=None): return self.global_settings.get(tag, default) def remove_field(self, tag, notify_subscribers=True): '''completely removes the specified tag from the metadata (if it exists) ''' #if self.get_field(tag) is not None: self.global_settings.pop(tag) if re.match(get_matchstring_for_subtag(2, 'Well'), tag): self.update_timeline(tag) if notify_subscribers: self.notify_subscribers(tag) print 'DEL FIELD: %s'%(tag) def get_action_tags(self): '''returns all existing TEMPORAL tags as list''' return [tag for tag in self.global_settings if tag.split('|')[0] in ('CellTransfer', 'Perturbation', 'Staining', 'AddProcess', 'DataAcquis', 'Notes')] def get_field_instances(self, tag_prefix): '''returns a list of unique instance ids for each tag beginning with tag_prefix''' ids = set([get_tag_instance(tag) for tag in self.global_settings if tag.startswith(tag_prefix)]) return list(ids) def get_attribute_list(self, tag_prefix): '''returns a list of attributes name for each tag beginning with tag_prefix''' ids = set([get_tag_attribute(tag) for tag in self.global_settings if tag.startswith(tag_prefix)]) return list(ids) def get_attribute_list_by_instance(self, tag_prefix, instance=None): '''returns a list of all attributes beginning with tag_prefix. If instance is passed in, only attributes of the given instance will be returned''' ids = set([get_tag_attribute(tag) for tag in self.global_settings if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instance is None or get_tag_instance(tag) == instance))]) return list(ids) #tags = [] #for tag in self.global_settings: #if ((tag_prefix is None or tag.startswith(tag_prefix)) and #(instance is None or get_tag_instance(tag) == instance)): #tag += [tag] #ids= set([get_tag_attribute(tag)]) #return list(ids) def get_attribute_dict(self, protocol): '''returns a dict mapping attribute names to their values for a given protocol. eg: get_attribute_dict('CellTransfer|Seed|1') --> {'SeedingDensity': 12, 'MediumUsed': 'agar', 'MediumAddatives': 'None', 'Trypsinization': True} ''' d = {} for tag in self.get_matching_tags('|*|'.join(protocol.rsplit('|',1))): if (get_tag_attribute(tag) not in ('Wells', 'EventTimepoint', 'Images', 'OriginWells')): d[get_tag_attribute(tag)] = self.global_settings[tag] return d def get_eventtype_list(self, tag_prefix): '''returns a list of attributes name for each tag beginning with tag_prefix''' ids = set([tag.split('|')[1] for tag in self.global_settings if tag.startswith(tag_prefix)]) return list(ids) def get_eventclass_list(self, tag_prefix): '''returns a list of event class name for each tag beginning with tag_prefix''' ids = set([tag.split('|')[0] for tag in self.global_settings if tag.startswith(tag_prefix)]) return list(ids) def get_field_tags(self, tag_prefix=None, instance=None): '''returns a list of all tags beginning with tag_prefix. If instance is passed in, only tags of the given instance will be returned''' tags = [] for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instance is None or get_tag_instance(tag) == instance)): tags += [tag] return tags def get_matching_tags(self, matchstring): '''returns a list of all tags matching matchstring matchstring -- a string that matches the tags you want eg: CellTransfer|* ''' tags = [] for tag in self.global_settings: match = True for m, subtag in map(None, matchstring.split('|'), tag.split('|')): if m != subtag and m not in ('*', None): match = False break if match: tags += [tag] return tags def get_protocol_instances(self, prefix): '''returns a list of protocol instance names for tags matching the given prefix. ''' return list(set([get_tag_instance(tag) for tag in self.get_field_tags(prefix)])) def get_new_protocol_id(self, prefix): '''returns an id string that hasn't been used for the given tag prefix prefix -- eg: CellTransfer|Seed ''' instances = self.get_protocol_instances(prefix) for i in xrange(1, 100000): if str(i) not in instances: return str(i) def get_instance_by_field_value(self, prefix, field_value): '''returns instance number given tag prefix and field value ''' return get_tag_instance([tag for tag, value in self.global_settings.iteritems() if value == field_value][0]) def get_stack_ids(self, prefix): '''returns the stack ids for a given type of vessels prefix e.g. ExptVessel|Tube''' return set([self.get_field(prefix+'|StackNo|%s'%instance) for instance in sorted(self.get_field_instances(prefix))]) def get_rep_vessel_instance(self, prefix, stack_id): ''' returns instance number of the vessel for this stack, since all vessels of a given stack has identical settings one instance represents others''' for instance in sorted(self.get_field_instances(prefix)): if self.get_field(prefix+'|StackNo|%s'%(instance)) == stack_id: return instance def clear(self): self.global_settings = {} PlateDesign.clear() # # TODO: # self.timeline = Timeline('TEST_STOCK') for matchstring, callbacks in self.subscribers.items(): for callback in callbacks: callback(None) def onTabClosing(self, event): event.Veto() dlg = wx.MessageDialog(None, 'Can not delete instance', 'Deleting..', wx.OK| wx.ICON_STOP) dlg.ShowModal() return def get_timeline(self): return self.timeline def does_tag_exists(self, tag_prefix, instnace=None): for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instnace is None or get_tag_instance(tag) == instnace)): return True else: return False def is_supp_protocol_filled(self, tag_prefix, instance=None): '''tag_prefix is always type|event e.g. AddProcess|Wash ''' for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instance is None or get_tag_instance(tag) == instance)): if (self.get_field(tag_prefix+'|ProtocolName|%s'%instance) is None) or (self.get_field(tag_prefix+'|Step1|%s'%instance) == ['', '', '']): return False else: return True def update_timeline(self, welltag): '''Updates the experiment metadata timeline event associated with the action and wells in welltag (eg: 'ExpNum|AddProcess|Spin|Wells|1|1') ''' platewell_ids = self.get_field(welltag, []) if platewell_ids == []: self.timeline.delete_event(welltag) else: event = self.timeline.get_event(welltag) if event is not None: event.set_well_ids(platewell_ids) else: self.timeline.add_event(welltag, platewell_ids) def save_to_file(self, file): f = open(file, 'w') for field, value in sorted(self.global_settings.items()): f.write('%s = %s\n'%(field, repr(value))) f.close() def save_settings(self, file, protocol): ''' saves settings in text file. the settings may include instrument settings, supp protocol, stock flask Format: attr = value where value may be text, int, list, etc. ''' instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) setting_type = get_tag_event(protocol) f = open(file,'w') f.write(setting_type+'\n') attributes = self.get_attribute_list_by_instance(tag_stump, instance) for attr in attributes: info = self.get_field(tag_stump+'|%s|%s' %(attr, instance)) print info f.write('%s = %s\n'%(attr, repr(info))) f.close() def save_supp_protocol_file(self, file, protocol): instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) f = open(file,'w') attributes = self.get_attribute_list_by_instance(tag_stump, instance) for attr in attributes: info = self.get_field(tag_stump+'|%s|%s' %(attr, instance)) if isinstance(info, list): f.write('%s|'%attr) for i, val in enumerate(info): if isinstance(val, tuple): print val elif i == len(info)-1: f.write('%s'%val) else: f.write('%s|'%val) f.write('\n') else: f.write('%s|%s\n'%(attr, info)) f.close() def load_from_file(self, file): # Populate the tag structure self.clear() f = open(file, 'r') for line in f: tag, value = line.split('=', 1) tag = tag.strip() self.set_field(tag, eval(value), notify_subscribers=False) f.close() # Populate PlateDesign PlateDesign.clear() for vessel_type in ('Plate', 'Flask', 'Dish', 'Coverslip', 'Tube'): prefix = 'ExptVessel|%s'%(vessel_type) for inst in self.get_field_instances(prefix): d = self.get_attribute_dict(prefix+'|'+inst) shape = d.get('Design', None) if shape is None: shape = (1,1) group = d.get('StackName', None) PlateDesign.add_plate(vessel_type, inst, shape, group) # Update everything for tag in self.global_settings: self.notify_subscribers(tag) # Update the bench time-slider # TODO: this is crappy try: import wx bench = wx.GetApp().get_bench() bench.set_time_interval(0, self.get_timeline().get_max_timepoint()) except:return def load_supp_protocol_file(self, file, protocol): instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) lines = [line.strip() for line in open(file)] if not lines: import wx dial = wx.MessageDialog(None, 'Supplementary protocol file is empty!!', 'Error', wx.OK | wx.ICON_ERROR) dial.ShowModal() return for line in lines: #line.rstrip('\n') line_info = line.split('|') attr = line_info.pop(0) if len(line_info)>1: self.set_field(tag_stump+'|%s|%s'%(attr, instance), line_info) else: self.set_field(tag_stump+'|%s|%s'%(attr, instance), line_info[0]) def load_settings(self, file, protocol): instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) f = open(file, 'r') lines = [line.strip() for line in f] lines.pop(0) # takes out the first line or the header where all setting type microscope/spin etc are written for line in lines: attr, value = line.split('=', 1) attr = attr.strip() tag = tag_stump+'|%s|%s'%(attr, instance) self.set_field(tag, eval(value), notify_subscribers=False) self.notify_subscribers(tag) f.close() def add_subscriber(self, callback, match_string): '''callback -- the function to be called match_string -- a regular expression string matching the tags you want to be notified of changes to ''' self.subscribers[match_string] = self.subscribers.get(match_string, []) + [callback] def remove_subscriber(self, callback): '''unsubscribe the given callback function. This MUST be called before a callback function is deleted. ''' for k, v in self.subscribers: if v == callback: self.subscribers.pop(k) def notify_subscribers(self, tag): for matchstring, callbacks in self.subscribers.items(): if re.match(matchstring, tag): for callback in callbacks: callback(tag) def getNM(self, nm): return int(nm.split('-')[0]), int(nm.split('-')[1]) def belongsTo(self, value, rangeStart, rangeEnd): if value >= rangeStart and value <= rangeEnd: return True return False def partition(self, lst, n): division = len(lst) / float(n) rlist = [lst[int(round(division * i)): int(round(division * (i + 1)))] [-1] for i in xrange(n) ] rlist.insert(0, lst[0]) return rlist def stringSplitByNumbers(self, x): r = re.compile('(\d+)') l = r.split(x) return [int(y) if y.isdigit() else y for y in l] def nmToRGB(self, w): # colour if w >= 380 and w < 440: R = -(w - 440.) / (440. - 350.) G = 0.0 B = 1.0 elif w >= 440 and w < 490: R = 0.0 G = (w - 440.) / (490. - 440.) B = 1.0 elif w >= 490 and w < 510: R = 0.0 G = 1.0 B = -(w - 510.) / (510. - 490.) elif w >= 510 and w < 580: R = (w - 510.) / (580. - 510.) G = 1.0 B = 0.0 elif w >= 580 and w < 645: R = 1.0 G = -(w - 645.) / (645. - 580.) B = 0.0 elif w >= 645 and w <= 780: R = 1.0 G = 0.0 B = 0.0 else: R = 0.0 G = 0.0 B = 0.0 # intensity correction if w >= 380 and w < 420: SSS = 0.3 + 0.7*(w - 350) / (420 - 350) elif w >= 420 and w <= 700: SSS = 1.0 elif w > 700 and w <= 780: SSS = 0.3 + 0.7*(780 - w) / (780 - 700) else: SSS = 0.0 SSS *= 255 return [int(SSS*R), int(SSS*G), int(SSS*B)] def decode_ch_component(self, component): '''this method decofify the components of the light path for a given channel 'LSR488' --> Laser 488nm, 'DMR567LP' ---> Long pass Dichroic Mirror 567nm etc.. ''' description = '' if component.startswith('LSR'): nm = re.sub('\D', '', component) description = nm+' nm Excitation laser ' if component.startswith('DMR'): nm = re.sub('\D', '', component) if component.endswith('LP'): description = nm+' nm Long Pass Dichroic Mirror' if component.endswith('SP'): description = nm+' nm Short Pass Dichroic Mirror' if component.startswith('FLT'): if component.endswith('LP'): description = re.sub('\D', '', component)+' nm Long Pass Filter' if component.endswith('SP'): description = re.sub('\D', '', component)+' nm Short Pass Filter' if component.endswith('BP'): description = (component.split('FLT')[1]).split('BP')[0]+' nm Band pass Filter' # this needs to be adjusted if component.startswith('DYE'): dye = component.split('_')[1] description = 'Dye used: %s' %dye if component.startswith('DTC'): volt = re.sub('\D', '', component) description = 'PMT voltage %s volts' %volt return description def setDyeList(self, emLow, emHgh): '''This method sets the list of dye for a given spectrum range''' dyeList = [] for dye in FLUOR_SPECTRUM: dyeLowNM, dyeHghNM = self.getNM(FLUOR_SPECTRUM[dye][1]) for wl in range(emLow, emHgh+1): if wl in range(dyeLowNM, dyeHghNM+1): dyeList.append(dye) #self.dyeListBox.Clear() return sorted(list(set(dyeList))) def saveData(self, ctrl, tag, settings_controls): if isinstance(ctrl, wx.ListBox) and ctrl.GetStringSelection() == 'Other': other = wx.GetTextFromUser('Insert Other', 'Other') ctrl.Append(other) ctrl.SetStringSelection(other) if len(tag.split('|'))>4: # get the relevant controls for this tag eg, duration, temp controls for this step subtags = [] info = [] for subtag in [t for t, c in settings_controls.items()]: if get_tag_stump(tag, 4) == get_tag_stump(subtag, 4): subtags.append(subtag) for i in range(0, len(subtags)): info.append('') for st in subtags: if isinstance(settings_controls[st], wx.Choice) or isinstance(settings_controls[st], wx.ListBox): info[int(st.split('|')[4])]=settings_controls[st].GetStringSelection() else: info[int(st.split('|')[4])]=settings_controls[st].GetValue() self.set_field(get_tag_stump(tag, 4), info) # get the core tag like AddProcess|Spin|Step|<instance> = [duration, description, temp] else: if isinstance(ctrl, wx.Choice) or isinstance(ctrl, wx.ListBox): self.set_field(tag, ctrl.GetStringSelection()) elif isinstance(ctrl, wx.DatePickerCtrl): date = ctrl.GetValue() self.set_field(tag, '%02d/%02d/%4d'%(date.Day, date.Month+1, date.Year)) else: user_input = ctrl.GetValue() self.set_field(tag, user_input) def get_seeded_sample(self, platewell_id): '''this method returns sample or cell line information for the selected well ''' timeline = self.get_timeline() timepoints = timeline.get_unique_timepoints() events_by_timepoint = timeline.get_events_by_timepoint() seeding_instances = [] for i, timepoint in enumerate(timepoints): for ev in events_by_timepoint[timepoint]: for well_id in ev.get_well_ids(): if well_id == platewell_id and ev.get_welltag().startswith('CellTransfer|Seed'): seeding_instances.append(ev.get_welltag()) return seeding_instances def get_sampleInstance(self, seed_tag): '''This method returns the stock culutre or sample instance for a given seeding tag CellTransfer|Seed|Wells|<instance> ''' instance = get_tag_instance(seed_tag) # if seed from stock culture if self.global_settings.has_key('CellTransfer|Seed|StockInstance|%s'%instance): return self.get_field('CellTransfer|Seed|StockInstance|%s'%instance) elif self.global_settings.has_key('CellTransfer|Seed|HarvestInstance|%s'%instance): return self.get_field('CellTransfer|Harvest|StockInstance|%s' %str(self.get_field('CellTransfer|Seed|HarvestInstance|%s'%instance))) #---------------------------------------------------------------------- def getStateRGB(self, trackTags): """This method returns the colour of the node given the history of the ancestor nodes events""" currRGB = (255, 255, 255, 100) for tag in trackTags: event = get_tag_event(tag) if event.startswith('Notes') or event.startswith('DataAcquis'): # since these are measurements or notes continue currRGB = (int((currRGB[0]+EVENT_RGB[event][0])/2), int((currRGB[1]+EVENT_RGB[event][1])/2), int((currRGB[2]+EVENT_RGB[event][2])/2), 100) return currRGB #---------------------------------------------------------------------- def getEventRGB(self, tag): """get all event tags for the passed node and returns the colour associated with the last event** Need to change**""" #currRGB = (255, 255, 255, 100) #if nodeTags: #tag = nodeTags.pop() event = get_tag_event(tag) if not event.startswith('Notes') or not event.startswith('DataAcquis'): # since these are measurements or notes return (EVENT_RGB[event][0], EVENT_RGB[event][1], EVENT_RGB[event][2], 100) else: return (255, 255, 255, 100) #---------------------------------------------------------------------- def getEventIcon(self, icon_size, act): """get the associated icon for the given action/event""" if act == 'Seed': icon = icons.seed.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Stock': icon = icons.stock.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Harvest': icon = icons.harvest.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Chem': icon = icons.treat.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Bio': icon = icons.dna.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Dye': icon = icons.stain.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Immuno': icon = icons.antibody.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Genetic': icon = icons.primer.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Spin': icon = icons.spin.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Wash': icon = icons.wash.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Dry': icon = icons.dry.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Medium': icon = icons.medium.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Incubator': icon = icons.incubator.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='HCS': icon = icons.staticimage.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='FCS': icon = icons.arrow_up.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='TLM': icon = icons.tlm.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Hint': #icon = icons.hint.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='CriticalPoint': #icon = icons.critical.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Rest': #icon = icons.rest.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='URL': #icon = icons.url.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Video': #icon = icons.video.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() return icon
class ExperimentSettings(Singleton): global_settings = {} timeline = Timeline('TEST_STOCK') subscribers = {} def __init__(self): pass def set_field(self, tag, value, notify_subscribers=True): self.global_settings[tag] = value if re.match(get_matchstring_for_subtag(2, 'Well'), tag): self.update_timeline(tag) if notify_subscribers: self.notify_subscribers(tag) print 'SET FIELD: %s = %s' % (tag, value) def get_field(self, tag, default=None): return self.global_settings.get(tag, default) def remove_field(self, tag, notify_subscribers=True): '''completely removes the specified tag from the metadata (if it exists) ''' #if self.get_field(tag) is not None: self.global_settings.pop(tag) if re.match(get_matchstring_for_subtag(2, 'Well'), tag): self.update_timeline(tag) if notify_subscribers: self.notify_subscribers(tag) print 'DEL FIELD: %s' % (tag) def get_action_tags(self): '''returns all existing TEMPORAL tags as list''' return [ tag for tag in self.global_settings if tag.split('|')[0] in ('CellTransfer', 'Perturbation', 'Staining', 'AddProcess', 'DataAcquis', 'Notes') ] def get_field_instances(self, tag_prefix): '''returns a list of unique instance ids for each tag beginning with tag_prefix''' ids = set([ get_tag_instance(tag) for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_attribute_list(self, tag_prefix): '''returns a list of attributes name for each tag beginning with tag_prefix''' ids = set([ get_tag_attribute(tag) for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_attribute_list_by_instance(self, tag_prefix, instance=None): '''returns a list of all attributes beginning with tag_prefix. If instance is passed in, only attributes of the given instance will be returned''' ids = set([ get_tag_attribute(tag) for tag in self.global_settings if ((tag_prefix is None or tag.startswith(tag_prefix)) and ( instance is None or get_tag_instance(tag) == instance)) ]) return list(ids) #tags = [] #for tag in self.global_settings: #if ((tag_prefix is None or tag.startswith(tag_prefix)) and #(instance is None or get_tag_instance(tag) == instance)): #tag += [tag] #ids= set([get_tag_attribute(tag)]) #return list(ids) def get_attribute_dict(self, protocol): '''returns a dict mapping attribute names to their values for a given protocol. eg: get_attribute_dict('CellTransfer|Seed|1') --> {'SeedingDensity': 12, 'MediumUsed': 'agar', 'MediumAddatives': 'None', 'Trypsinization': True} ''' d = {} for tag in self.get_matching_tags('|*|'.join(protocol.rsplit('|', 1))): if (get_tag_attribute(tag) not in ('Wells', 'EventTimepoint', 'Images', 'OriginWells')): d[get_tag_attribute(tag)] = self.global_settings[tag] return d def get_eventtype_list(self, tag_prefix): '''returns a list of attributes name for each tag beginning with tag_prefix''' ids = set([ tag.split('|')[1] for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_eventclass_list(self, tag_prefix): '''returns a list of event class name for each tag beginning with tag_prefix''' ids = set([ tag.split('|')[0] for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_field_tags(self, tag_prefix=None, instance=None): '''returns a list of all tags beginning with tag_prefix. If instance is passed in, only tags of the given instance will be returned''' tags = [] for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instance is None or get_tag_instance(tag) == instance)): tags += [tag] return tags def get_matching_tags(self, matchstring): '''returns a list of all tags matching matchstring matchstring -- a string that matches the tags you want eg: CellTransfer|* ''' tags = [] for tag in self.global_settings: match = True for m, subtag in map(None, matchstring.split('|'), tag.split('|')): if m != subtag and m not in ('*', None): match = False break if match: tags += [tag] return tags def get_protocol_instances(self, prefix): '''returns a list of protocol instance names for tags matching the given prefix. ''' return list( set([get_tag_instance(tag) for tag in self.get_field_tags(prefix)])) def get_new_protocol_id(self, prefix): '''returns an id string that hasn't been used for the given tag prefix prefix -- eg: CellTransfer|Seed ''' instances = self.get_protocol_instances(prefix) for i in xrange(1, 100000): if str(i) not in instances: return str(i) def get_instance_by_field_value(self, prefix, field_value): '''returns instance number given tag prefix and field value ''' return get_tag_instance([ tag for tag, value in self.global_settings.iteritems() if value == field_value ][0]) def get_stack_ids(self, prefix): '''returns the stack ids for a given type of vessels prefix e.g. ExptVessel|Tube''' return set([ self.get_field(prefix + '|StackNo|%s' % instance) for instance in sorted(self.get_field_instances(prefix)) ]) def get_rep_vessel_instance(self, prefix, stack_id): ''' returns instance number of the vessel for this stack, since all vessels of a given stack has identical settings one instance represents others''' for instance in sorted(self.get_field_instances(prefix)): if self.get_field(prefix + '|StackNo|%s' % (instance)) == stack_id: return instance def clear(self): self.global_settings = {} PlateDesign.clear() # # TODO: # self.timeline = Timeline('TEST_STOCK') for matchstring, callbacks in self.subscribers.items(): for callback in callbacks: callback(None) def onTabClosing(self, event): event.Veto() dlg = wx.MessageDialog(None, 'Can not delete instance', 'Deleting..', wx.OK | wx.ICON_STOP) dlg.ShowModal() return def get_timeline(self): return self.timeline def does_tag_exists(self, tag_prefix, instnace=None): for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instnace is None or get_tag_instance(tag) == instnace)): return True else: return False def is_supp_protocol_filled(self, tag_prefix, instance=None): '''tag_prefix is always type|event e.g. AddProcess|Wash ''' for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instance is None or get_tag_instance(tag) == instance)): if (self.get_field(tag_prefix + '|ProtocolName|%s' % instance) is None) or (self.get_field(tag_prefix + '|Step1|%s' % instance) == ['', '', '']): return False else: return True def update_timeline(self, welltag): '''Updates the experiment metadata timeline event associated with the action and wells in welltag (eg: 'ExpNum|AddProcess|Spin|Wells|1|1') ''' platewell_ids = self.get_field(welltag, []) if platewell_ids == []: self.timeline.delete_event(welltag) else: event = self.timeline.get_event(welltag) if event is not None: event.set_well_ids(platewell_ids) else: self.timeline.add_event(welltag, platewell_ids) def save_to_file(self, file): f = open(file, 'w') for field, value in sorted(self.global_settings.items()): f.write('%s = %s\n' % (field, repr(value))) f.close() def save_settings(self, file, protocol): ''' saves settings in text file. the settings may include instrument settings, supp protocol, stock flask Format: attr = value where value may be text, int, list, etc. ''' instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) setting_type = get_tag_event(protocol) f = open(file, 'w') f.write(setting_type + '\n') attributes = self.get_attribute_list_by_instance(tag_stump, instance) for attr in attributes: info = self.get_field(tag_stump + '|%s|%s' % (attr, instance)) print info f.write('%s = %s\n' % (attr, repr(info))) f.close() def save_supp_protocol_file(self, file, protocol): instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) f = open(file, 'w') attributes = self.get_attribute_list_by_instance(tag_stump, instance) for attr in attributes: info = self.get_field(tag_stump + '|%s|%s' % (attr, instance)) if isinstance(info, list): f.write('%s|' % attr) for i, val in enumerate(info): if isinstance(val, tuple): print val elif i == len(info) - 1: f.write('%s' % val) else: f.write('%s|' % val) f.write('\n') else: f.write('%s|%s\n' % (attr, info)) f.close() def load_from_file(self, file): # Populate the tag structure self.clear() f = open(file, 'r') for line in f: tag, value = line.split('=', 1) tag = tag.strip() self.set_field(tag, eval(value), notify_subscribers=False) f.close() # Populate PlateDesign PlateDesign.clear() for vessel_type in ('Plate', 'Flask', 'Dish', 'Coverslip', 'Tube'): prefix = 'ExptVessel|%s' % (vessel_type) for inst in self.get_field_instances(prefix): d = self.get_attribute_dict(prefix + '|' + inst) shape = d.get('Design', None) if shape is None: shape = (1, 1) group = d.get('StackName', None) PlateDesign.add_plate(vessel_type, inst, shape, group) # Update everything for tag in self.global_settings: self.notify_subscribers(tag) # Update the bench time-slider # TODO: this is crappy try: import wx bench = wx.GetApp().get_bench() bench.set_time_interval(0, self.get_timeline().get_max_timepoint()) except: return def load_supp_protocol_file(self, file, protocol): instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) lines = [line.strip() for line in open(file)] if not lines: import wx dial = wx.MessageDialog(None, 'Supplementary protocol file is empty!!', 'Error', wx.OK | wx.ICON_ERROR) dial.ShowModal() return for line in lines: #line.rstrip('\n') line_info = line.split('|') attr = line_info.pop(0) if len(line_info) > 1: self.set_field(tag_stump + '|%s|%s' % (attr, instance), line_info) else: self.set_field(tag_stump + '|%s|%s' % (attr, instance), line_info[0]) def load_settings(self, file, protocol): instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) f = open(file, 'r') lines = [line.strip() for line in f] lines.pop( 0 ) # takes out the first line or the header where all setting type microscope/spin etc are written for line in lines: attr, value = line.split('=', 1) attr = attr.strip() tag = tag_stump + '|%s|%s' % (attr, instance) self.set_field(tag, eval(value), notify_subscribers=False) self.notify_subscribers(tag) f.close() def add_subscriber(self, callback, match_string): '''callback -- the function to be called match_string -- a regular expression string matching the tags you want to be notified of changes to ''' self.subscribers[match_string] = self.subscribers.get( match_string, []) + [callback] def remove_subscriber(self, callback): '''unsubscribe the given callback function. This MUST be called before a callback function is deleted. ''' for k, v in self.subscribers: if v == callback: self.subscribers.pop(k) def notify_subscribers(self, tag): for matchstring, callbacks in self.subscribers.items(): if re.match(matchstring, tag): for callback in callbacks: callback(tag) def getNM(self, nm): return int(nm.split('-')[0]), int(nm.split('-')[1]) def belongsTo(self, value, rangeStart, rangeEnd): if value >= rangeStart and value <= rangeEnd: return True return False def partition(self, lst, n): division = len(lst) / float(n) rlist = [ lst[int(round(division * i)):int(round(division * (i + 1)))][-1] for i in xrange(n) ] rlist.insert(0, lst[0]) return rlist def stringSplitByNumbers(self, x): r = re.compile('(\d+)') l = r.split(x) return [int(y) if y.isdigit() else y for y in l] def nmToRGB(self, w): # colour if w >= 380 and w < 440: R = -(w - 440.) / (440. - 350.) G = 0.0 B = 1.0 elif w >= 440 and w < 490: R = 0.0 G = (w - 440.) / (490. - 440.) B = 1.0 elif w >= 490 and w < 510: R = 0.0 G = 1.0 B = -(w - 510.) / (510. - 490.) elif w >= 510 and w < 580: R = (w - 510.) / (580. - 510.) G = 1.0 B = 0.0 elif w >= 580 and w < 645: R = 1.0 G = -(w - 645.) / (645. - 580.) B = 0.0 elif w >= 645 and w <= 780: R = 1.0 G = 0.0 B = 0.0 else: R = 0.0 G = 0.0 B = 0.0 # intensity correction if w >= 380 and w < 420: SSS = 0.3 + 0.7 * (w - 350) / (420 - 350) elif w >= 420 and w <= 700: SSS = 1.0 elif w > 700 and w <= 780: SSS = 0.3 + 0.7 * (780 - w) / (780 - 700) else: SSS = 0.0 SSS *= 255 return [int(SSS * R), int(SSS * G), int(SSS * B)] def decode_ch_component(self, component): '''this method decofify the components of the light path for a given channel 'LSR488' --> Laser 488nm, 'DMR567LP' ---> Long pass Dichroic Mirror 567nm etc.. ''' description = '' if component.startswith('LSR'): nm = re.sub('\D', '', component) description = nm + ' nm Excitation laser ' if component.startswith('DMR'): nm = re.sub('\D', '', component) if component.endswith('LP'): description = nm + ' nm Long Pass Dichroic Mirror' if component.endswith('SP'): description = nm + ' nm Short Pass Dichroic Mirror' if component.startswith('FLT'): if component.endswith('LP'): description = re.sub('\D', '', component) + ' nm Long Pass Filter' if component.endswith('SP'): description = re.sub('\D', '', component) + ' nm Short Pass Filter' if component.endswith('BP'): description = (component.split('FLT')[1]).split('BP')[ 0] + ' nm Band pass Filter' # this needs to be adjusted if component.startswith('DYE'): dye = component.split('_')[1] description = 'Dye used: %s' % dye if component.startswith('DTC'): volt = re.sub('\D', '', component) description = 'PMT voltage %s volts' % volt return description def setDyeList(self, emLow, emHgh): '''This method sets the list of dye for a given spectrum range''' dyeList = [] for dye in FLUOR_SPECTRUM: dyeLowNM, dyeHghNM = self.getNM(FLUOR_SPECTRUM[dye][1]) for wl in range(emLow, emHgh + 1): if wl in range(dyeLowNM, dyeHghNM + 1): dyeList.append(dye) #self.dyeListBox.Clear() return sorted(list(set(dyeList))) def saveData(self, ctrl, tag, settings_controls): if isinstance(ctrl, wx.ListBox) and ctrl.GetStringSelection() == 'Other': other = wx.GetTextFromUser('Insert Other', 'Other') ctrl.Append(other) ctrl.SetStringSelection(other) if len(tag.split('|')) > 4: # get the relevant controls for this tag eg, duration, temp controls for this step subtags = [] info = [] for subtag in [t for t, c in settings_controls.items()]: if get_tag_stump(tag, 4) == get_tag_stump(subtag, 4): subtags.append(subtag) for i in range(0, len(subtags)): info.append('') for st in subtags: if isinstance(settings_controls[st], wx.Choice) or isinstance( settings_controls[st], wx.ListBox): info[int(st.split( '|')[4])] = settings_controls[st].GetStringSelection() else: info[int( st.split('|')[4])] = settings_controls[st].GetValue() self.set_field( get_tag_stump(tag, 4), info ) # get the core tag like AddProcess|Spin|Step|<instance> = [duration, description, temp] else: if isinstance(ctrl, wx.Choice) or isinstance(ctrl, wx.ListBox): self.set_field(tag, ctrl.GetStringSelection()) elif isinstance(ctrl, wx.DatePickerCtrl): date = ctrl.GetValue() self.set_field( tag, '%02d/%02d/%4d' % (date.Day, date.Month + 1, date.Year)) else: user_input = ctrl.GetValue() self.set_field(tag, user_input) def get_seeded_sample(self, platewell_id): '''this method returns sample or cell line information for the selected well ''' timeline = self.get_timeline() timepoints = timeline.get_unique_timepoints() events_by_timepoint = timeline.get_events_by_timepoint() seeding_instances = [] for i, timepoint in enumerate(timepoints): for ev in events_by_timepoint[timepoint]: for well_id in ev.get_well_ids(): if well_id == platewell_id and ev.get_welltag().startswith( 'CellTransfer|Seed'): seeding_instances.append(ev.get_welltag()) return seeding_instances def get_sampleInstance(self, seed_tag): '''This method returns the stock culutre or sample instance for a given seeding tag CellTransfer|Seed|Wells|<instance> ''' instance = get_tag_instance(seed_tag) # if seed from stock culture if self.global_settings.has_key('CellTransfer|Seed|StockInstance|%s' % instance): return self.get_field('CellTransfer|Seed|StockInstance|%s' % instance) elif self.global_settings.has_key( 'CellTransfer|Seed|HarvestInstance|%s' % instance): return self.get_field( 'CellTransfer|Harvest|StockInstance|%s' % str( self.get_field( 'CellTransfer|Seed|HarvestInstance|%s' % instance))) #---------------------------------------------------------------------- def getStateRGB(self, trackTags): """This method returns the colour of the node given the history of the ancestor nodes events""" currRGB = (255, 255, 255, 100) for tag in trackTags: event = get_tag_event(tag) if event.startswith('Notes') or event.startswith( 'DataAcquis'): # since these are measurements or notes continue currRGB = (int((currRGB[0] + EVENT_RGB[event][0]) / 2), int((currRGB[1] + EVENT_RGB[event][1]) / 2), int((currRGB[2] + EVENT_RGB[event][2]) / 2), 100) return currRGB #---------------------------------------------------------------------- def getEventRGB(self, tag): """get all event tags for the passed node and returns the colour associated with the last event** Need to change**""" #currRGB = (255, 255, 255, 100) #if nodeTags: #tag = nodeTags.pop() event = get_tag_event(tag) if not event.startswith('Notes') or not event.startswith( 'DataAcquis'): # since these are measurements or notes return (EVENT_RGB[event][0], EVENT_RGB[event][1], EVENT_RGB[event][2], 100) else: return (255, 255, 255, 100) #---------------------------------------------------------------------- def getEventIcon(self, icon_size, act): """get the associated icon for the given action/event""" if act == 'Seed': icon = icons.seed.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Stock': icon = icons.stock.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Harvest': icon = icons.harvest.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Chem': icon = icons.treat.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Bio': icon = icons.dna.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Dye': icon = icons.stain.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Immuno': icon = icons.antibody.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Genetic': icon = icons.primer.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Spin': icon = icons.spin.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Wash': icon = icons.wash.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Dry': icon = icons.dry.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Medium': icon = icons.medium.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Incubator': icon = icons.incubator.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'HCS': icon = icons.staticimage.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'FCS': icon = icons.arrow_up.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'TLM': icon = icons.tlm.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Hint': #icon = icons.hint.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='CriticalPoint': #icon = icons.critical.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Rest': #icon = icons.rest.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='URL': #icon = icons.url.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Video': #icon = icons.video.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() return icon
class ExperimentSettings(Singleton): global_settings = {} timeline = Timeline('TEST_STOCK') subscribers = {} #curr_dir = os.path.dirname(os.path.abspath(__file__)) #save_file_path = curr_dir+'\\temporary_experiment.txt' # first assign it to the temp directory save_file_path = None def __init__(self): pass def set_field(self, tag, value, notify_subscribers=True): self.global_settings[tag] = value if re.match(get_matchstring_for_subtag(2, 'Well'), tag): self.update_timeline(tag) if notify_subscribers: self.notify_subscribers(tag) print 'SET FIELD: %s = %s' % (tag, value) def get_field(self, tag, default=None): return self.global_settings.get(tag, default) def remove_field(self, tag, notify_subscribers=True): '''completely removes the specified tag from the metadata (if it exists) ''' #if self.get_field(tag) is not None: self.global_settings.pop(tag) if re.match(get_matchstring_for_subtag(2, 'Well'), tag): self.update_timeline(tag) if notify_subscribers: self.notify_subscribers(tag) print 'DEL FIELD: %s' % (tag) def remove_harvest_seed_tags(self, h_inst, s_inst): '''removes all associated tags with coupled harvest seed tags e.g density, steps etc''' h_attrs = self.get_attribute_list_by_instance('Transfer|Harvest', h_inst) s_attrs = self.get_attribute_list_by_instance('Transfer|Seed', s_inst) if h_attrs: for h_attr in h_attrs: self.remove_field('Transfer|Harvest|%s|%s' % (h_attr, h_inst), notify_subscribers=False) if s_attrs: for s_attr in s_attrs: self.remove_field('Transfer|Seed|%s|%s' % (s_attr, s_inst), notify_subscribers=False) def remove_associated_dataacquis_tag(self, wells): '''removes all image tags associated with this timepoint and wells e.g. DataAcquis|*|Images|*|timepoint|[(Plate_Well), ()]''' image_tags = self.get_matching_tags('DataAcquis|*|Images|*|*|%s' % str(wells)) if image_tags: for i_tag in image_tags: self.remove_field(i_tag) def remove_timeline_attachments(self, timepoint): '''removes all notes and attachment from the timeline at the given timepoint''' note_tags = self.get_matching_tags('Notes|*|%s|*' % timepoint) attach_tags = self.get_matching_tags('Attachments|*|%s|*' % timepoint) if note_tags: for n_tag in note_tags: self.remove_field(n_tag) if attach_tags: for a_tag in attach_tags: self.remove_field(a_tag) def get_action_tags(self): '''returns all existing TEMPORAL tags as list''' return [ tag for tag in self.global_settings if tag.split('|')[0] in ('Transfer', 'Perturbation', 'Labeling', 'AddProcess', 'DataAcquis', 'InstProcess', 'Notes') ] def get_field_instances(self, tag_prefix): '''returns a list of unique instance ids for each tag beginning with tag_prefix''' ids = set([ get_tag_instance(tag) for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_attribute_list(self, tag_prefix): '''returns a list of attributes name for each tag beginning with tag_prefix''' ids = set([ get_tag_attribute(tag) for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_attribute_list_by_instance(self, tag_prefix, instance=None): '''returns a list of all attributes beginning with tag_prefix. If instance is passed in, only attributes of the given instance will be returned''' ids = set([ get_tag_attribute(tag) for tag in self.global_settings if ((tag_prefix is None or tag.startswith(tag_prefix)) and ( instance is None or get_tag_instance(tag) == instance)) ]) return list(ids) #tags = [] #for tag in self.global_settings: #if ((tag_prefix is None or tag.startswith(tag_prefix)) and #(instance is None or get_tag_instance(tag) == instance)): #tag += [tag] #ids= set([get_tag_attribute(tag)]) #return list(ids) def get_attribute_dict(self, protocol): '''returns a dict mapping attribute names to their values for a given protocol. eg: get_attribute_dict('Transfer|Seed|1') --> {'SeedingDensity': 12, 'MediumUsed': 'agar', 'MediumAddatives': 'None', 'Trypsinization': True} ''' d = {} for tag in self.get_matching_tags('|*|'.join(protocol.rsplit('|', 1))): if (get_tag_attribute(tag) not in ('Wells', 'EventTimepoint', 'Images', 'OriginWells')): d[get_tag_attribute(tag)] = self.global_settings[tag] return d def get_eventtype_list(self, tag_prefix): '''returns a list of attributes name for each tag beginning with tag_prefix''' ids = set([ tag.split('|')[1] for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_eventclass_list(self, tag_prefix): '''returns a list of event class name for each tag beginning with tag_prefix''' ids = set([ tag.split('|')[0] for tag in self.global_settings if tag.startswith(tag_prefix) ]) return list(ids) def get_field_tags(self, tag_prefix=None, instance=None): '''returns a list of all tags beginning with tag_prefix. If instance is passed in, only tags of the given instance will be returned''' tags = [] for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instance is None or get_tag_instance(tag) == instance)): tags += [tag] return tags def get_matching_tags(self, matchstring): '''returns a list of all tags matching matchstring matchstring -- a string that matches the tags you want eg: Transfer|* ''' tags = [] for tag in self.global_settings: match = True for m, subtag in map(None, matchstring.split('|'), tag.split('|')): if m != subtag and m not in ('*', None): match = False break if match: tags += [tag] return tags def get_protocol_instances(self, prefix): '''returns a list of protocol instance names for tags matching the given prefix. ''' return list( set([get_tag_instance(tag) for tag in self.get_field_tags(prefix)])) def get_new_protocol_id(self, prefix): '''returns an id string that hasn't been used for the given tag prefix prefix -- eg: Transfer|Seed ''' instances = self.get_protocol_instances(prefix) for i in xrange(1, 100000): if str(i) not in instances: return str(i) def get_instance_by_field_value(self, prefix, field_value): '''returns instance number given tag prefix and field value ''' return get_tag_instance([ tag for tag, value in self.global_settings.iteritems() if value == field_value ][0]) def get_stack_ids(self, prefix): '''returns the stack ids for a given type of vessels prefix e.g. ExptVessel|Tube''' return set([ self.get_field(prefix + '|StackNo|%s' % instance) for instance in sorted(self.get_field_instances(prefix)) ]) def get_rep_vessel_instance(self, prefix, stack_id): ''' returns instance number of the vessel for this stack, since all vessels of a given stack has identical settings one instance represents others''' for instance in sorted(self.get_field_instances(prefix)): if self.get_field(prefix + '|StackNo|%s' % (instance)) == stack_id: return instance def clear(self): self.global_settings = {} PlateDesign.clear() # # TODO: # self.timeline = Timeline('TEST_STOCK') for matchstring, callbacks in self.subscribers.items(): for callback in callbacks: callback(None) def onTabClosing(self, event): event.Veto() dlg = wx.MessageDialog(None, 'Can not delete instance', 'Deleting..', wx.OK | wx.ICON_STOP) dlg.ShowModal() return def get_timeline(self): return self.timeline def does_tag_exists(self, tag_prefix, instnace=None): for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instnace is None or get_tag_instance(tag) == instnace)): return True else: return False def is_supp_protocol_filled(self, tag_prefix, instance=None): '''tag_prefix is always type|event e.g. AddProcess|Wash ''' for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instance is None or get_tag_instance(tag) == instance)): if (self.get_field(tag_prefix + '|ProtocolName|%s' % instance) is None) or (self.get_field(tag_prefix + '|Step1|%s' % instance) == ['', '', '']): return False else: return True def update_timeline(self, welltag): '''Updates the experiment metadata timeline event associated with the action and wells in welltag (eg: 'ExpNum|AddProcess|Spin|Wells|1|1') ''' platewell_ids = self.get_field(welltag, []) if platewell_ids == []: self.timeline.delete_event(welltag) else: event = self.timeline.get_event(welltag) if event is not None: event.set_well_ids(platewell_ids) else: self.timeline.add_event(welltag, platewell_ids) def save_file_dialogue(self): exp_date = self.get_field('Overview|Project|ExptDate') exp_num = self.get_field('Overview|Project|ExptNum') exp_title = self.get_field('Overview|Project|Title') if self.save_file_path: self.save_to_file() #import ntpath #filename = os.path.splitext(ntpath.basename(self.save_file_path))[0] else: filename = 'new_experiment.txt' if None not in [exp_date, exp_num, exp_title]: day, month, year = exp_date.split('/') filename = '%s%s%s_%s_%s.txt' % (year, month, day, exp_num, exp_title) dlg = wx.FileDialog(None, message='Saving experimental protocol...', defaultDir=os.getcwd(), defaultFile=filename, wildcard='.txt', style=wx.SAVE | wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: self.save_file_path = dlg.GetPath() self.save_to_file() def save_as_file_dialogue(self): exp_date = self.get_field('Overview|Project|ExptDate') exp_num = self.get_field('Overview|Project|ExptNum') exp_title = self.get_field('Overview|Project|Title') if self.save_file_path: import ntpath filename = os.path.splitext(ntpath.basename( self.save_file_path))[0] else: filename = 'new_experiment.txt' if None not in [exp_date, exp_num, exp_title]: day, month, year = exp_date.split('/') filename = '%s%s%s_%s_%s.txt' % (year, month, day, exp_num, exp_title) dlg = wx.FileDialog(None, message='Saving experimental protocol...', defaultDir=os.getcwd(), defaultFile=filename, wildcard='.txt', style=wx.SAVE | wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: self.save_file_path = dlg.GetPath() self.save_to_file() def save_to_file(self): if self.save_file_path: try: f = open(self.save_file_path, 'w') f.write(VERSION + '\n') for field, value in sorted(self.global_settings.items()): f.write('%s = %s\n' % (field, repr(value))) f.close() except IOError: import wx dial = wx.MessageDialog( None, 'No permission to create temporary experimental file in current directory\nPlease save file in separate directory.', 'Error', wx.OK | wx.ICON_ERROR) if dial.ShowModal() == wx.ID_OK: self.save_as_file_dialogue() def saveData(self, ctrl, tag, settings_controls): if isinstance(ctrl, wx.ListBox) and ctrl.GetStringSelection() == 'Other': other = wx.GetTextFromUser('Insert Other', 'Other') ctrl.Append(other) ctrl.SetStringSelection(other) if len(tag.split('|')) > 4: # get the relevant controls for this tag eg, duration, temp controls for this step subtags = [] info = [] for subtag in [t for t, c in settings_controls.items()]: if get_tag_stump(tag, 4) == get_tag_stump(subtag, 4): subtags.append(subtag) for i in range(0, len(subtags)): info.append('') for st in subtags: if isinstance(settings_controls[st], wx.Choice) or isinstance( settings_controls[st], wx.ListBox): info[int(st.split( '|')[4])] = settings_controls[st].GetStringSelection() #settings_controls[st].SetToolTipString(settings_controls[st].GetStringSelection()) else: info[int( st.split('|')[4])] = settings_controls[st].GetValue() #settings_controls[st].SetToolTipString(settings_controls[st].GetValue()) self.set_field( get_tag_stump(tag, 4), info ) # get the core tag like AddProcess|Spin|Step|<instance> = [duration, description, temp] else: if isinstance(ctrl, wx.Choice) or isinstance(ctrl, wx.ListBox): self.set_field(tag, ctrl.GetStringSelection()) #ctrl.SetToolTipString(ctrl.GetStringSelection()) elif isinstance(ctrl, wx.DatePickerCtrl): date = ctrl.GetValue() self.set_field( tag, '%02d/%02d/%4d' % (date.Day, date.Month + 1, date.Year)) else: user_input = ctrl.GetValue() self.set_field(tag, user_input) #ctrl.SetToolTipString(ctrl.GetValue()) def saving_settings(self, protocol, tag, m_tags): import wx if not self.get_field(tag): dial = wx.MessageDialog(None, 'Please provide a settings/protocol name', 'Error', wx.OK | wx.ICON_ERROR) dial.ShowModal() return if self.checkMandatoryTags(m_tags): filename = self.get_field(tag) + '.txt' dlg = wx.FileDialog(None, message='Saving ...', defaultDir=os.getcwd(), defaultFile=filename, wildcard='.txt', style=wx.SAVE | wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: dirname = dlg.GetDirectory() filename = dlg.GetFilename() file_path = os.path.join(dirname, filename) self.save_settings(file_path, protocol) def save_settings(self, file, protocol): ''' saves settings in text file. the settings may include instrument settings, supp protocol, stock flask Format: attr = value where value may be text, int, list, etc. ''' instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) setting_type = get_tag_event(protocol) f = open(file, 'w') f.write(setting_type + '\n') attributes = list( set(self.get_attribute_list_by_instance(tag_stump, instance))) if 'Wells' in attributes: attributes.remove('Wells') for attr in attributes: value = self.get_field(tag_stump + '|%s|%s' % (attr, instance)) if attr.endswith('Instance'): f.write('Dependency%s = %s\n' % (attr, repr(value)) ) # to get the ...Instance which will be overwritten for d_attr, d_val in self.get_attribute_dict( '%s|%s' % (DEPENDENCY[get_tag_event(protocol)], value)).iteritems(): f.write('Dependency%s = %s\n' % (d_attr, repr(d_val))) else: f.write('%s = %s\n' % (attr, repr(value))) f.close() def load_from_file(self, file, menuitem): # Populate the tag structure self.clear() f = open(file, 'r') lines = [line.strip() for line in f] if not lines.pop(0).startswith('ProtocolNavigator'): import wx dial = wx.MessageDialog( None, 'Selected file is not a ProtocolNavigator file', 'Error', wx.OK | wx.ICON_ERROR) dial.ShowModal() return for line in lines: tag, value = line.split('=', 1) tag = tag.strip() self.set_field(tag, eval(value), notify_subscribers=False) f.close() # Disable the open file menu menuitem.Enable(False) # index the file path self.save_file_path = file #import ntpath #self.temp_file_path = os.path.dirname(os.path.abspath(file))+os.path.splitext(ntpath.basename(self.save_file_path))[0]+'_temp.txt' # Populate PlateDesign PlateDesign.clear() for vessel_type in ('Plate', 'Flask', 'Dish', 'Coverslip', 'Tube'): prefix = 'ExptVessel|%s' % (vessel_type) for inst in self.get_field_instances(prefix): d = self.get_attribute_dict(prefix + '|' + inst) shape = d.get('Design', None) if shape is None: shape = (1, 1) group = d.get('StackName', None) PlateDesign.add_plate(vessel_type, inst, shape, group) # Update everything for tag in self.global_settings: self.notify_subscribers(tag) # Update the bench time-slider # TODO: this is crappy try: import wx bench = wx.GetApp().get_bench() bench.set_time_interval(0, self.get_timeline().get_max_timepoint()) except: return def load_supp_protocol_file(self, file, protocol): instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) lines = [line.strip() for line in open(file)] if not lines: import wx dial = wx.MessageDialog(None, 'Sub-process file is empty!!', 'Error', wx.OK | wx.ICON_ERROR) dial.ShowModal() return for line in lines: #line.rstrip('\n') line_info = line.split('|') attr = line_info.pop(0) if len(line_info) > 1: self.set_field(tag_stump + '|%s|%s' % (attr, instance), line_info) else: self.set_field(tag_stump + '|%s|%s' % (attr, instance), line_info[0]) def load_settings(self, file, protocol): instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) f = open(file, 'r') lines = [line.strip() for line in f] event = lines.pop( 0 ) # takes out the first line or the header where all setting type microscope/spin etc are written attributes = {} for line in lines: attr, value = line.split('=', 1) attributes[attr.strip()] = value # set all dependency attributes e.g. Centifugation depends on Centrifuge dependecny_attrs = [s for s in attributes if 'Dependency' in s] if dependecny_attrs: d_inst = self.get_new_protocol_id(DEPENDENCY[event]) for d_attr in dependecny_attrs: if d_attr.endswith('Instance'): tag = tag_stump + '|%s|%s' % ( d_attr.split('Dependency')[1], instance) self.set_field(tag, d_inst, notify_subscribers=False) self.notify_subscribers(tag) del attributes[d_attr] else: tag = DEPENDENCY[event] + '|%s|%s' % ( d_attr.split('Dependency')[1], d_inst) self.set_field(tag, eval(attributes[d_attr]), notify_subscribers=False) self.notify_subscribers(tag) del attributes[d_attr] # set rest of the attributes for attr in attributes: tag = tag_stump + '|%s|%s' % (attr, instance) self.set_field(tag, eval(attributes[attr]), notify_subscribers=False) self.notify_subscribers(tag) f.close() #for line in lines: #attr, value = line.split('=', 1) #attr = attr.strip() #tag = tag_stump+'|%s|%s'%(attr, instance) #self.set_field(tag, eval(value), notify_subscribers=False) #self.notify_subscribers(tag) #f.close() def add_subscriber(self, callback, match_string): '''callback -- the function to be called match_string -- a regular expression string matching the tags you want to be notified of changes to ''' self.subscribers[match_string] = self.subscribers.get( match_string, []) + [callback] def remove_subscriber(self, callback): '''unsubscribe the given callback function. This MUST be called before a callback function is deleted. ''' for k, v in self.subscribers: if v == callback: self.subscribers.pop(k) def notify_subscribers(self, tag): for matchstring, callbacks in self.subscribers.items(): if re.match(matchstring, tag): #self.save_to_temp_file() # update info to the temp file for callback in callbacks: callback(tag) def getNM(self, nm): return int(nm.split('-')[0]), int(nm.split('-')[1]) def belongsTo(self, value, rangeStart, rangeEnd): if value >= rangeStart and value <= rangeEnd: return True return False def partition(self, lst, n): division = len(lst) / float(n) rlist = [ lst[int(round(division * i)):int(round(division * (i + 1)))][-1] for i in xrange(n) ] rlist.insert(0, lst[0]) return rlist def stringSplitByNumbers(self, x): r = re.compile('(\d+)') l = r.split(x) return [int(y) if y.isdigit() else y for y in l] def nmToRGB(self, w): # colour if w >= 380 and w < 440: R = -(w - 440.) / (440. - 350.) G = 0.0 B = 1.0 elif w >= 440 and w < 490: R = 0.0 G = (w - 440.) / (490. - 440.) B = 1.0 elif w >= 490 and w < 510: R = 0.0 G = 1.0 B = -(w - 510.) / (510. - 490.) elif w >= 510 and w < 580: R = (w - 510.) / (580. - 510.) G = 1.0 B = 0.0 elif w >= 580 and w < 645: R = 1.0 G = -(w - 645.) / (645. - 580.) B = 0.0 elif w >= 645 and w <= 780: R = 1.0 G = 0.0 B = 0.0 else: R = 0.0 G = 0.0 B = 0.0 # intensity correction if w >= 380 and w < 420: SSS = 0.3 + 0.7 * (w - 350) / (420 - 350) elif w >= 420 and w <= 700: SSS = 1.0 elif w > 700 and w <= 780: SSS = 0.3 + 0.7 * (780 - w) / (780 - 700) else: SSS = 0.0 SSS *= 255 return [int(SSS * R), int(SSS * G), int(SSS * B)] def decode_ch_component(self, component): '''this method decofify the components of the light path for a given channel 'LSR488' --> Laser 488nm, 'DMR567LP' ---> Long pass Dichroic Mirror 567nm etc.. ''' description = '' if component.startswith('LSR'): nm = re.sub('\D', '', component) description = nm + ' nm Excitation laser ' if component.startswith('DMR'): nm = re.sub('\D', '', component) if component.endswith('LP'): description = nm + ' nm Long Pass Dichroic Mirror' if component.endswith('SP'): description = nm + ' nm Short Pass Dichroic Mirror' if component.startswith('FLT'): if component.endswith('LP'): description = re.sub('\D', '', component) + ' nm Long Pass Filter' if component.endswith('SP'): description = re.sub('\D', '', component) + ' nm Short Pass Filter' if component.endswith('BP'): description = (component.split('FLT')[1]).split('BP')[ 0] + ' nm Band pass Filter' # this needs to be adjusted if component.startswith('SLT'): ratio = component.split('SLT')[1] description = re.sub('/', ':', ratio) + ' Beam Splitter' if component.startswith('DYE'): dye = component.split('_')[1] description = 'Dye used: %s' % dye if component.startswith('DTC'): volt = re.sub('\D', '', component) description = 'PMT voltage %s volts' % volt return description def setDyeList(self, emLow, emHgh): '''This method sets the list of dye for a given spectrum range''' dyeList = [] for dye in FLUOR_SPECTRUM: dyeLowNM, dyeHghNM = self.getNM(FLUOR_SPECTRUM[dye][1]) for wl in range(emLow, emHgh + 1): if wl in range(dyeLowNM, dyeHghNM + 1): dyeList.append(dye) #self.dyeListBox.Clear() return sorted(list(set(dyeList))) def get_seeded_sample(self, platewell_id): '''this method returns sample or cell line information for the selected well ''' timeline = self.get_timeline() timepoints = timeline.get_unique_timepoints() events_by_timepoint = timeline.get_events_by_timepoint() seeding_instances = [] for i, timepoint in enumerate(timepoints): for ev in events_by_timepoint[timepoint]: for well_id in ev.get_well_ids(): if well_id == platewell_id and ev.get_welltag().startswith( 'Transfer|Seed'): seeding_instances.append(ev.get_welltag()) return seeding_instances #---------------------------------------------------------------------- def get_sampleInstance(self, seed_tag): '''This method returns the stock culutre or sample instance for a given seeding tag Transfer|Seed|Wells|<instance> ''' instance = get_tag_instance(seed_tag) # if seed from stock culture if self.global_settings.has_key('Transfer|Seed|CellLineInstance|%s' % instance): return self.get_field('Transfer|Seed|CellLineInstance|%s' % instance) elif self.global_settings.has_key('Transfer|Seed|HarvestInstance|%s' % instance): return self.get_field('Transfer|Harvest|CellLineInstance|%s' % str( self.get_field('Transfer|Seed|HarvestInstance|%s' % instance))) #---------------------------------------------------------------------- def getStateRGB(self, trackTags): """This method returns the colour of the node given the history of the ancestor nodes events""" currRGB = (255, 255, 255, 100) for tag in trackTags: event = get_tag_event(tag) if event.startswith('Notes') or event.startswith( 'DataAcquis'): # since these are measurements or notes continue currRGB = (int((currRGB[0] + EVENT_RGB[event][0]) / 2), int((currRGB[1] + EVENT_RGB[event][1]) / 2), int((currRGB[2] + EVENT_RGB[event][2]) / 2), 100) return currRGB #---------------------------------------------------------------------- def getEventRGB(self, tag): """get all event tags for the passed node and returns the colour associated with the last event** Need to change**""" #currRGB = (255, 255, 255, 100) #if nodeTags: #tag = nodeTags.pop() event = get_tag_event(tag) if not event.startswith('Notes') or not event.startswith( 'DataAcquis'): # since these are measurements or notes return (EVENT_RGB[event][0], EVENT_RGB[event][1], EVENT_RGB[event][2], 100) else: return (255, 255, 255, 100) #---------------------------------------------------------------------- def getEventIcon(self, icon_size, act): """get the associated icon for the given action/event""" if act == 'Seed': icon = icons.seed.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'CellLine': icon = icons.stock.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Harvest': icon = icons.harvest.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Chemical': icon = icons.treat.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Biological': icon = icons.dna.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Physical': icon = icons.physical.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Dye': icon = icons.stain.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Immuno': icon = icons.antibody.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Genetic': icon = icons.primer.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Centrifugation': icon = icons.spin.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Wash': icon = icons.wash.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Drying': icon = icons.drying.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Medium': icon = icons.medium.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Initiation': icon = icons.initiation.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Storage': icon = icons.storage.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'Incubation': icon = icons.incubator.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'RheoManipulation': icon = icons.rheometer.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'HCS': icon = icons.hcs.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'FCS': icon = icons.fcs.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'TLM': icon = icons.tlm.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'RHE': icon = icons.rhe.Scale( icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Hint': #icon = icons.hint.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Text': #icon = icons.critical.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Rest': #icon = icons.rest.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='URL': #icon = icons.url.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='MultiMedia': #icon = icons.video.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() return icon #---------------------------------------------------------------------- def get_Row_Numbers(self, protocol, token): """This method returs TAGS with similar elements eg. 'AddProcess|Rheology|Gas1|1' 'AddProcess|Rheology|Gas2|1' etc""" tag_stump = get_tag_stump(protocol, 2) instance = get_tag_attribute(protocol) return sorted(self.get_attribute_list_by_instance( tag_stump + '|%s' % token, instance), key=self.stringSplitByNumbers) #---------------------------------------------------------------------- def setLabelColour(self, tags, labels): """Change mandatory label colour Red-->Green when filled""" for tag in tags: if self.get_field(tag): labels[tag].SetForegroundColour(('#006600')) labels[tag].Refresh() else: labels[tag].SetForegroundColour(wx.RED) labels[tag].Refresh() #---------------------------------------------------------------------- def checkMandatoryTags(self, tags): """Checks whether the mandatory fields/tags being filled""" for tag in tags: if not self.get_field(tag): import wx dial = wx.MessageDialog( None, 'Please fill %s mandatory field' % get_tag_attribute(tag), 'Error', wx.OK | wx.ICON_ERROR) dial.ShowModal() return return True #---------------------------------------------------------------------- def alphanumeric_sort(self, lst): """sort alphanumeric strings in a list e.g. [Plate1, Plate11, Tube2]""" re_natural = re.compile('[0-9]+|[^0-9]+') return [(1, int(c)) if c.isdigit() else (0, c.lower()) for c in re_natural.findall(lst)] + [lst] #---------------------------------------------------------------------- def last_seed_instance(self, instance): """finds the last seeding instance that is associated with a harvest instance""" for inst in list(reversed(range(int(instance)))): if 'Transfer|Seed|HarvestInstance|%s' % str(inst) is not None: return str(inst) #---------------------------------------------------------------------- def get_cellLine_Name(self, inst, mode): """returns cell Line name given the seeding/harvesting (mode) instance that is realted with a harvest instance if mode is None, it refers to Harvest_Seed type of seeding instance""" if mode is 'H': return self.get_field('Sample|CellLine|Name|%s' % str( self.get_field( 'Transfer|Harvest|CellLineInstance|%s' % str(inst)))) if mode is 'S': return self.get_field('Sample|CellLine|Name|%s' % str( self.get_field( 'Transfer|Seed|CellLineInstance|%s' % str(inst)))) if mode is 'HS': return self.get_field('Sample|CellLine|Name|%s' % str( self.get_field('Transfer|Harvest|CellLineInstance|%s' % str( self.get_field( 'Transfer|Seed|HarvestInstance|%s' % str(inst))))))
class ExperimentSettings(Singleton): global_settings = {} timeline = Timeline('TEST_STOCK') subscribers = {} #curr_dir = os.path.dirname(os.path.abspath(__file__)) #save_file_path = curr_dir+'\\temporary_experiment.txt' # first assign it to the temp directory save_file_path = None def __init__(self): pass def set_field(self, tag, value, notify_subscribers=True): self.global_settings[tag] = value if re.match(get_matchstring_for_subtag(2, 'Well'), tag): self.update_timeline(tag) if notify_subscribers: self.notify_subscribers(tag) print 'SET FIELD: %s = %s'%(tag, value) def get_field(self, tag, default=None): return self.global_settings.get(tag, default) def remove_field(self, tag, notify_subscribers=True): '''completely removes the specified tag from the metadata (if it exists) ''' #if self.get_field(tag) is not None: self.global_settings.pop(tag) if re.match(get_matchstring_for_subtag(2, 'Well'), tag): self.update_timeline(tag) if notify_subscribers: self.notify_subscribers(tag) print 'DEL FIELD: %s'%(tag) def remove_harvest_seed_tags(self, h_inst, s_inst): '''removes all associated tags with coupled harvest seed tags e.g density, steps etc''' h_attrs = self.get_attribute_list_by_instance('Transfer|Harvest', h_inst) s_attrs = self.get_attribute_list_by_instance('Transfer|Seed', s_inst) if h_attrs: for h_attr in h_attrs: self.remove_field('Transfer|Harvest|%s|%s'%(h_attr, h_inst), notify_subscribers =False) if s_attrs: for s_attr in s_attrs: self.remove_field('Transfer|Seed|%s|%s'%(s_attr, s_inst), notify_subscribers =False) def remove_associated_dataacquis_tag(self, wells): '''removes all image tags associated with this timepoint and wells e.g. DataAcquis|*|Images|*|timepoint|[(Plate_Well), ()]''' image_tags = self.get_matching_tags('DataAcquis|*|Images|*|*|%s'%str(wells)) if image_tags: for i_tag in image_tags: self.remove_field(i_tag) def remove_timeline_attachments(self, timepoint): '''removes all notes and attachment from the timeline at the given timepoint''' note_tags = self.get_matching_tags('Notes|*|%s|*'%timepoint) attach_tags = self.get_matching_tags('Attachments|*|%s|*'%timepoint) if note_tags: for n_tag in note_tags: self.remove_field(n_tag) if attach_tags: for a_tag in attach_tags: self.remove_field(a_tag) def get_action_tags(self): '''returns all existing TEMPORAL tags as list''' return [tag for tag in self.global_settings if tag.split('|')[0] in ('Transfer', 'Perturbation', 'Labeling', 'AddProcess', 'DataAcquis', 'InstProcess', 'Notes')] def get_field_instances(self, tag_prefix): '''returns a list of unique instance ids for each tag beginning with tag_prefix''' ids = set([get_tag_instance(tag) for tag in self.global_settings if tag.startswith(tag_prefix)]) return list(ids) def get_attribute_list(self, tag_prefix): '''returns a list of attributes name for each tag beginning with tag_prefix''' ids = set([get_tag_attribute(tag) for tag in self.global_settings if tag.startswith(tag_prefix)]) return list(ids) def get_attribute_list_by_instance(self, tag_prefix, instance=None): '''returns a list of all attributes beginning with tag_prefix. If instance is passed in, only attributes of the given instance will be returned''' ids = set([get_tag_attribute(tag) for tag in self.global_settings if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instance is None or get_tag_instance(tag) == instance))]) return list(ids) #tags = [] #for tag in self.global_settings: #if ((tag_prefix is None or tag.startswith(tag_prefix)) and #(instance is None or get_tag_instance(tag) == instance)): #tag += [tag] #ids= set([get_tag_attribute(tag)]) #return list(ids) def get_attribute_dict(self, protocol): '''returns a dict mapping attribute names to their values for a given protocol. eg: get_attribute_dict('Transfer|Seed|1') --> {'SeedingDensity': 12, 'MediumUsed': 'agar', 'MediumAddatives': 'None', 'Trypsinization': True} ''' d = {} for tag in self.get_matching_tags('|*|'.join(protocol.rsplit('|',1))): if (get_tag_attribute(tag) not in ('Wells', 'EventTimepoint', 'Images', 'OriginWells')): d[get_tag_attribute(tag)] = self.global_settings[tag] return d def get_eventtype_list(self, tag_prefix): '''returns a list of attributes name for each tag beginning with tag_prefix''' ids = set([tag.split('|')[1] for tag in self.global_settings if tag.startswith(tag_prefix)]) return list(ids) def get_eventclass_list(self, tag_prefix): '''returns a list of event class name for each tag beginning with tag_prefix''' ids = set([tag.split('|')[0] for tag in self.global_settings if tag.startswith(tag_prefix)]) return list(ids) def get_field_tags(self, tag_prefix=None, instance=None): '''returns a list of all tags beginning with tag_prefix. If instance is passed in, only tags of the given instance will be returned''' tags = [] for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instance is None or get_tag_instance(tag) == instance)): tags += [tag] return tags def get_matching_tags(self, matchstring): '''returns a list of all tags matching matchstring matchstring -- a string that matches the tags you want eg: Transfer|* ''' tags = [] for tag in self.global_settings: match = True for m, subtag in map(None, matchstring.split('|'), tag.split('|')): if m != subtag and m not in ('*', None): match = False break if match: tags += [tag] return tags def get_protocol_instances(self, prefix): '''returns a list of protocol instance names for tags matching the given prefix. ''' return list(set([get_tag_instance(tag) for tag in self.get_field_tags(prefix)])) def get_new_protocol_id(self, prefix): '''returns an id string that hasn't been used for the given tag prefix prefix -- eg: Transfer|Seed ''' instances = self.get_protocol_instances(prefix) for i in xrange(1, 100000): if str(i) not in instances: return str(i) def get_instance_by_field_value(self, prefix, field_value): '''returns instance number given tag prefix and field value ''' return get_tag_instance([tag for tag, value in self.global_settings.iteritems() if value == field_value][0]) def get_stack_ids(self, prefix): '''returns the stack ids for a given type of vessels prefix e.g. ExptVessel|Tube''' return set([self.get_field(prefix+'|StackNo|%s'%instance) for instance in sorted(self.get_field_instances(prefix))]) def get_rep_vessel_instance(self, prefix, stack_id): ''' returns instance number of the vessel for this stack, since all vessels of a given stack has identical settings one instance represents others''' for instance in sorted(self.get_field_instances(prefix)): if self.get_field(prefix+'|StackNo|%s'%(instance)) == stack_id: return instance def clear(self): self.global_settings = {} PlateDesign.clear() # # TODO: # self.timeline = Timeline('TEST_STOCK') for matchstring, callbacks in self.subscribers.items(): for callback in callbacks: callback(None) def onTabClosing(self, event): event.Veto() dlg = wx.MessageDialog(None, 'Can not delete instance', 'Deleting..', wx.OK| wx.ICON_STOP) dlg.ShowModal() return def get_timeline(self): return self.timeline def does_tag_exists(self, tag_prefix, instnace=None): for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instnace is None or get_tag_instance(tag) == instnace)): return True else: return False def is_supp_protocol_filled(self, tag_prefix, instance=None): '''tag_prefix is always type|event e.g. AddProcess|Wash ''' for tag in self.global_settings: if ((tag_prefix is None or tag.startswith(tag_prefix)) and (instance is None or get_tag_instance(tag) == instance)): if (self.get_field(tag_prefix+'|ProtocolName|%s'%instance) is None) or (self.get_field(tag_prefix+'|Step1|%s'%instance) == ['', '', '']): return False else: return True def update_timeline(self, welltag): '''Updates the experiment metadata timeline event associated with the action and wells in welltag (eg: 'ExpNum|AddProcess|Spin|Wells|1|1') ''' platewell_ids = self.get_field(welltag, []) if platewell_ids == []: self.timeline.delete_event(welltag) else: event = self.timeline.get_event(welltag) if event is not None: event.set_well_ids(platewell_ids) else: self.timeline.add_event(welltag, platewell_ids) def save_file_dialogue(self): exp_date = self.get_field('Overview|Project|ExptDate') exp_num = self.get_field('Overview|Project|ExptNum') exp_title = self.get_field('Overview|Project|Title') if self.save_file_path: self.save_to_file() #import ntpath #filename = os.path.splitext(ntpath.basename(self.save_file_path))[0] else: filename = 'new_experiment.txt' if None not in [exp_date, exp_num, exp_title]: day, month, year = exp_date.split('/') filename = '%s%s%s_%s_%s.txt'%(year, month, day , exp_num, exp_title) dlg = wx.FileDialog(None, message='Saving experimental protocol...', defaultDir=os.getcwd(), defaultFile=filename, wildcard='.txt', style=wx.SAVE|wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: self.save_file_path = dlg.GetPath() self.save_to_file() def save_as_file_dialogue(self): exp_date = self.get_field('Overview|Project|ExptDate') exp_num = self.get_field('Overview|Project|ExptNum') exp_title = self.get_field('Overview|Project|Title') if self.save_file_path: import ntpath filename = os.path.splitext(ntpath.basename(self.save_file_path))[0] else: filename = 'new_experiment.txt' if None not in [exp_date, exp_num, exp_title]: day, month, year = exp_date.split('/') filename = '%s%s%s_%s_%s.txt'%(year, month, day , exp_num, exp_title) dlg = wx.FileDialog(None, message='Saving experimental protocol...', defaultDir=os.getcwd(), defaultFile=filename, wildcard='.txt', style=wx.SAVE|wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: self.save_file_path = dlg.GetPath() self.save_to_file() def save_to_file(self): if self.save_file_path: try: f = open(self.save_file_path, 'w') f.write(VERSION+'\n') for field, value in sorted(self.global_settings.items()): f.write('%s = %s\n'%(field, repr(value))) f.close() except IOError: import wx dial = wx.MessageDialog(None, 'No permission to create temporary experimental file in current directory\nPlease save file in separate directory.', 'Error', wx.OK | wx.ICON_ERROR) if dial.ShowModal() == wx.ID_OK: self.save_as_file_dialogue() def saveData(self, ctrl, tag, settings_controls): if isinstance(ctrl, wx.ListBox) and ctrl.GetStringSelection() == 'Other': other = wx.GetTextFromUser('Insert Other', 'Other') ctrl.Append(other) ctrl.SetStringSelection(other) if len(tag.split('|'))>4: # get the relevant controls for this tag eg, duration, temp controls for this step subtags = [] info = [] for subtag in [t for t, c in settings_controls.items()]: if get_tag_stump(tag, 4) == get_tag_stump(subtag, 4): subtags.append(subtag) for i in range(0, len(subtags)): info.append('') for st in subtags: if isinstance(settings_controls[st], wx.Choice) or isinstance(settings_controls[st], wx.ListBox): info[int(st.split('|')[4])]=settings_controls[st].GetStringSelection() #settings_controls[st].SetToolTipString(settings_controls[st].GetStringSelection()) else: info[int(st.split('|')[4])]=settings_controls[st].GetValue() #settings_controls[st].SetToolTipString(settings_controls[st].GetValue()) self.set_field(get_tag_stump(tag, 4), info) # get the core tag like AddProcess|Spin|Step|<instance> = [duration, description, temp] else: if isinstance(ctrl, wx.Choice) or isinstance(ctrl, wx.ListBox): self.set_field(tag, ctrl.GetStringSelection()) #ctrl.SetToolTipString(ctrl.GetStringSelection()) elif isinstance(ctrl, wx.DatePickerCtrl): date = ctrl.GetValue() self.set_field(tag, '%02d/%02d/%4d'%(date.Day, date.Month+1, date.Year)) else: user_input = ctrl.GetValue() self.set_field(tag, user_input) #ctrl.SetToolTipString(ctrl.GetValue()) def saving_settings(self, protocol, tag, m_tags): import wx if not self.get_field(tag): dial = wx.MessageDialog(None, 'Please provide a settings/protocol name', 'Error', wx.OK | wx.ICON_ERROR) dial.ShowModal() return if self.checkMandatoryTags(m_tags): filename = self.get_field(tag)+'.txt' dlg = wx.FileDialog(None, message='Saving ...', defaultDir=os.getcwd(), defaultFile=filename, wildcard='.txt', style=wx.SAVE|wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: dirname=dlg.GetDirectory() filename=dlg.GetFilename() file_path = os.path.join(dirname, filename) self.save_settings(file_path, protocol) def save_settings(self, file, protocol): ''' saves settings in text file. the settings may include instrument settings, supp protocol, stock flask Format: attr = value where value may be text, int, list, etc. ''' instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) setting_type = get_tag_event(protocol) f = open(file,'w') f.write(setting_type+'\n') attributes = list(set(self.get_attribute_list_by_instance(tag_stump, instance))) if 'Wells' in attributes: attributes.remove('Wells') for attr in attributes: value = self.get_field(tag_stump+'|%s|%s' %(attr, instance)) if attr.endswith('Instance'): f.write('Dependency%s = %s\n'%(attr, repr(value))) # to get the ...Instance which will be overwritten for d_attr, d_val in self.get_attribute_dict('%s|%s' %(DEPENDENCY[get_tag_event(protocol)], value)).iteritems(): f.write('Dependency%s = %s\n'%(d_attr, repr(d_val))) else: f.write('%s = %s\n'%(attr, repr(value))) f.close() def load_from_file(self, file, menuitem): # Populate the tag structure self.clear() f = open(file, 'r') lines = [line.strip() for line in f] if not lines.pop(0).startswith('ProtocolNavigator'): import wx dial = wx.MessageDialog(None, 'Selected file is not a ProtocolNavigator file', 'Error', wx.OK | wx.ICON_ERROR) dial.ShowModal() return for line in lines: tag, value = line.split('=', 1) tag = tag.strip() self.set_field(tag, eval(value), notify_subscribers=False) f.close() # Disable the open file menu menuitem.Enable(False) # index the file path self.save_file_path = file #import ntpath #self.temp_file_path = os.path.dirname(os.path.abspath(file))+os.path.splitext(ntpath.basename(self.save_file_path))[0]+'_temp.txt' # Populate PlateDesign PlateDesign.clear() for vessel_type in ('Plate', 'Flask', 'Dish', 'Coverslip', 'Tube'): prefix = 'ExptVessel|%s'%(vessel_type) for inst in self.get_field_instances(prefix): d = self.get_attribute_dict(prefix+'|'+inst) shape = d.get('Design', None) if shape is None: shape = (1,1) group = d.get('StackName', None) PlateDesign.add_plate(vessel_type, inst, shape, group) # Update everything for tag in self.global_settings: self.notify_subscribers(tag) # Update the bench time-slider # TODO: this is crappy try: import wx bench = wx.GetApp().get_bench() bench.set_time_interval(0, self.get_timeline().get_max_timepoint()) except:return def load_supp_protocol_file(self, file, protocol): instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) lines = [line.strip() for line in open(file)] if not lines: import wx dial = wx.MessageDialog(None, 'Sub-process file is empty!!', 'Error', wx.OK | wx.ICON_ERROR) dial.ShowModal() return for line in lines: #line.rstrip('\n') line_info = line.split('|') attr = line_info.pop(0) if len(line_info)>1: self.set_field(tag_stump+'|%s|%s'%(attr, instance), line_info) else: self.set_field(tag_stump+'|%s|%s'%(attr, instance), line_info[0]) def load_settings(self, file, protocol): instance = get_tag_attribute(protocol) tag_stump = get_tag_stump(protocol, 2) f = open(file, 'r') lines = [line.strip() for line in f] event = lines.pop(0) # takes out the first line or the header where all setting type microscope/spin etc are written attributes = {} for line in lines: attr, value = line.split('=', 1) attributes[attr.strip()] = value # set all dependency attributes e.g. Centifugation depends on Centrifuge dependecny_attrs = [s for s in attributes if 'Dependency' in s] if dependecny_attrs: d_inst = self.get_new_protocol_id(DEPENDENCY[event]) for d_attr in dependecny_attrs: if d_attr.endswith('Instance'): tag = tag_stump+'|%s|%s'%(d_attr.split('Dependency')[1], instance) self.set_field(tag, d_inst, notify_subscribers=False) self.notify_subscribers(tag) del attributes[d_attr] else: tag = DEPENDENCY[event]+'|%s|%s'%(d_attr.split('Dependency')[1], d_inst) self.set_field(tag, eval(attributes[d_attr]), notify_subscribers=False) self.notify_subscribers(tag) del attributes[d_attr] # set rest of the attributes for attr in attributes: tag = tag_stump+'|%s|%s'%(attr, instance) self.set_field(tag, eval(attributes[attr]), notify_subscribers=False) self.notify_subscribers(tag) f.close() #for line in lines: #attr, value = line.split('=', 1) #attr = attr.strip() #tag = tag_stump+'|%s|%s'%(attr, instance) #self.set_field(tag, eval(value), notify_subscribers=False) #self.notify_subscribers(tag) #f.close() def add_subscriber(self, callback, match_string): '''callback -- the function to be called match_string -- a regular expression string matching the tags you want to be notified of changes to ''' self.subscribers[match_string] = self.subscribers.get(match_string, []) + [callback] def remove_subscriber(self, callback): '''unsubscribe the given callback function. This MUST be called before a callback function is deleted. ''' for k, v in self.subscribers: if v == callback: self.subscribers.pop(k) def notify_subscribers(self, tag): for matchstring, callbacks in self.subscribers.items(): if re.match(matchstring, tag): #self.save_to_temp_file() # update info to the temp file for callback in callbacks: callback(tag) def getNM(self, nm): return int(nm.split('-')[0]), int(nm.split('-')[1]) def belongsTo(self, value, rangeStart, rangeEnd): if value >= rangeStart and value <= rangeEnd: return True return False def partition(self, lst, n): division = len(lst) / float(n) rlist = [lst[int(round(division * i)): int(round(division * (i + 1)))] [-1] for i in xrange(n) ] rlist.insert(0, lst[0]) return rlist def stringSplitByNumbers(self, x): r = re.compile('(\d+)') l = r.split(x) return [int(y) if y.isdigit() else y for y in l] def nmToRGB(self, w): # colour if w >= 380 and w < 440: R = -(w - 440.) / (440. - 350.) G = 0.0 B = 1.0 elif w >= 440 and w < 490: R = 0.0 G = (w - 440.) / (490. - 440.) B = 1.0 elif w >= 490 and w < 510: R = 0.0 G = 1.0 B = -(w - 510.) / (510. - 490.) elif w >= 510 and w < 580: R = (w - 510.) / (580. - 510.) G = 1.0 B = 0.0 elif w >= 580 and w < 645: R = 1.0 G = -(w - 645.) / (645. - 580.) B = 0.0 elif w >= 645 and w <= 780: R = 1.0 G = 0.0 B = 0.0 else: R = 0.0 G = 0.0 B = 0.0 # intensity correction if w >= 380 and w < 420: SSS = 0.3 + 0.7*(w - 350) / (420 - 350) elif w >= 420 and w <= 700: SSS = 1.0 elif w > 700 and w <= 780: SSS = 0.3 + 0.7*(780 - w) / (780 - 700) else: SSS = 0.0 SSS *= 255 return [int(SSS*R), int(SSS*G), int(SSS*B)] def decode_ch_component(self, component): '''this method decofify the components of the light path for a given channel 'LSR488' --> Laser 488nm, 'DMR567LP' ---> Long pass Dichroic Mirror 567nm etc.. ''' description = '' if component.startswith('LSR'): nm = re.sub('\D', '', component) description = nm+' nm Excitation laser ' if component.startswith('DMR'): nm = re.sub('\D', '', component) if component.endswith('LP'): description = nm+' nm Long Pass Dichroic Mirror' if component.endswith('SP'): description = nm+' nm Short Pass Dichroic Mirror' if component.startswith('FLT'): if component.endswith('LP'): description = re.sub('\D', '', component)+' nm Long Pass Filter' if component.endswith('SP'): description = re.sub('\D', '', component)+' nm Short Pass Filter' if component.endswith('BP'): description = (component.split('FLT')[1]).split('BP')[0]+' nm Band pass Filter' # this needs to be adjusted if component.startswith('SLT'): ratio = component.split('SLT')[1] description = re.sub('/', ':', ratio)+' Beam Splitter' if component.startswith('DYE'): dye = component.split('_')[1] description = 'Dye used: %s' %dye if component.startswith('DTC'): volt = re.sub('\D', '', component) description = 'PMT voltage %s volts' %volt return description def setDyeList(self, emLow, emHgh): '''This method sets the list of dye for a given spectrum range''' dyeList = [] for dye in FLUOR_SPECTRUM: dyeLowNM, dyeHghNM = self.getNM(FLUOR_SPECTRUM[dye][1]) for wl in range(emLow, emHgh+1): if wl in range(dyeLowNM, dyeHghNM+1): dyeList.append(dye) #self.dyeListBox.Clear() return sorted(list(set(dyeList))) def get_seeded_sample(self, platewell_id): '''this method returns sample or cell line information for the selected well ''' timeline = self.get_timeline() timepoints = timeline.get_unique_timepoints() events_by_timepoint = timeline.get_events_by_timepoint() seeding_instances = [] for i, timepoint in enumerate(timepoints): for ev in events_by_timepoint[timepoint]: for well_id in ev.get_well_ids(): if well_id == platewell_id and ev.get_welltag().startswith('Transfer|Seed'): seeding_instances.append(ev.get_welltag()) return seeding_instances #---------------------------------------------------------------------- def get_sampleInstance(self, seed_tag): '''This method returns the stock culutre or sample instance for a given seeding tag Transfer|Seed|Wells|<instance> ''' instance = get_tag_instance(seed_tag) # if seed from stock culture if self.global_settings.has_key('Transfer|Seed|CellLineInstance|%s'%instance): return self.get_field('Transfer|Seed|CellLineInstance|%s'%instance) elif self.global_settings.has_key('Transfer|Seed|HarvestInstance|%s'%instance): return self.get_field('Transfer|Harvest|CellLineInstance|%s' %str(self.get_field('Transfer|Seed|HarvestInstance|%s'%instance))) #---------------------------------------------------------------------- def getStateRGB(self, trackTags): """This method returns the colour of the node given the history of the ancestor nodes events""" currRGB = (255, 255, 255, 100) for tag in trackTags: event = get_tag_event(tag) if event.startswith('Notes') or event.startswith('DataAcquis'): # since these are measurements or notes continue currRGB = (int((currRGB[0]+EVENT_RGB[event][0])/2), int((currRGB[1]+EVENT_RGB[event][1])/2), int((currRGB[2]+EVENT_RGB[event][2])/2), 100) return currRGB #---------------------------------------------------------------------- def getEventRGB(self, tag): """get all event tags for the passed node and returns the colour associated with the last event** Need to change**""" #currRGB = (255, 255, 255, 100) #if nodeTags: #tag = nodeTags.pop() event = get_tag_event(tag) if not event.startswith('Notes') or not event.startswith('DataAcquis'): # since these are measurements or notes return (EVENT_RGB[event][0], EVENT_RGB[event][1], EVENT_RGB[event][2], 100) else: return (255, 255, 255, 100) #---------------------------------------------------------------------- def getEventIcon(self, icon_size, act): """get the associated icon for the given action/event""" if act == 'Seed': icon = icons.seed.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act == 'CellLine': icon = icons.stock.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Harvest': icon = icons.harvest.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Chemical': icon = icons.treat.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Biological': icon = icons.dna.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Physical': icon = icons.physical.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Dye': icon = icons.stain.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Immuno': icon = icons.antibody.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Genetic': icon = icons.primer.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Centrifugation': icon = icons.spin.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Wash': icon = icons.wash.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Drying': icon = icons.drying.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Medium': icon = icons.medium.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Initiation': icon = icons.initiation.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Storage': icon = icons.storage.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='Incubation': icon = icons.incubator.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='RheoManipulation': icon = icons.rheometer.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='HCS': icon = icons.hcs.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='FCS': icon = icons.fcs.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='TLM': icon = icons.tlm.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() elif act =='RHE': icon = icons.rhe.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Hint': #icon = icons.hint.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Text': #icon = icons.critical.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='Rest': #icon = icons.rest.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='URL': #icon = icons.url.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() #elif act =='MultiMedia': #icon = icons.video.Scale(icon_size, icon_size, quality=wx.IMAGE_QUALITY_HIGH).ConvertToBitmap() return icon #---------------------------------------------------------------------- def get_Row_Numbers(self, protocol, token): """This method returs TAGS with similar elements eg. 'AddProcess|Rheology|Gas1|1' 'AddProcess|Rheology|Gas2|1' etc""" tag_stump = get_tag_stump(protocol, 2) instance = get_tag_attribute(protocol) return sorted(self.get_attribute_list_by_instance(tag_stump+'|%s'%token, instance), key = self.stringSplitByNumbers) #---------------------------------------------------------------------- def setLabelColour(self, tags, labels): """Change mandatory label colour Red-->Green when filled""" for tag in tags: if self.get_field(tag): labels[tag].SetForegroundColour(('#006600')) labels[tag].Refresh() else: labels[tag].SetForegroundColour(wx.RED) labels[tag].Refresh() #---------------------------------------------------------------------- def checkMandatoryTags(self, tags): """Checks whether the mandatory fields/tags being filled""" for tag in tags: if not self.get_field(tag): import wx dial = wx.MessageDialog(None, 'Please fill %s mandatory field' %get_tag_attribute(tag), 'Error', wx.OK | wx.ICON_ERROR) dial.ShowModal() return return True #---------------------------------------------------------------------- def alphanumeric_sort(self, lst): """sort alphanumeric strings in a list e.g. [Plate1, Plate11, Tube2]""" re_natural = re.compile('[0-9]+|[^0-9]+') return [(1, int(c)) if c.isdigit() else (0, c.lower()) for c in re_natural.findall(lst)] + [lst] #---------------------------------------------------------------------- def last_seed_instance(self, instance): """finds the last seeding instance that is associated with a harvest instance""" for inst in list(reversed(range(int(instance)))): if 'Transfer|Seed|HarvestInstance|%s'%str(inst) is not None: return str(inst) #---------------------------------------------------------------------- def get_cellLine_Name(self, inst, mode): """returns cell Line name given the seeding/harvesting (mode) instance that is realted with a harvest instance if mode is None, it refers to Harvest_Seed type of seeding instance""" if mode is 'H': return self.get_field('Sample|CellLine|Name|%s' %str(self.get_field('Transfer|Harvest|CellLineInstance|%s'%str(inst)))) if mode is 'S': return self.get_field('Sample|CellLine|Name|%s' %str(self.get_field('Transfer|Seed|CellLineInstance|%s'%str(inst)))) if mode is 'HS': return self.get_field('Sample|CellLine|Name|%s' %str(self.get_field('Transfer|Harvest|CellLineInstance|%s' %str(self.get_field('Transfer|Seed|HarvestInstance|%s' %str(inst))))))