class PathwayMiningApp(ui.AnalysisApp): def __init__(self, **kwargs): super(PathwayMiningApp, self).__init__(**kwargs) # Define automatic mapping (settings will determine the route; allow manual tweaks later) self.addDataToolBar() #self.addExperimentToolBar() self.config.set_defaults({ '/Data/MiningActive': False, '/Data/MiningDepth': 5, '/Data/MiningType': 'c', '/Data/MiningRelative': False, '/Data/MiningShared': True, }) #t = self.getCreatedToolbar('Pathway mining', 'pathway_mining') #miningSetup = QAction( QIcon( os.path.join( self.plugin.path, 'icon-16.png' ) ), 'Set up pathway mining \u2026', self.m) #miningSetup.setStatusTip('Set parameters for pathway mining') #miningSetup.triggered.connect(self.onMiningSettings) #t.addAction(miningSetup) self.data.add_input('input_1') # Add input slot self.data.add_input('input_2') # Add input slot self.data.add_input('input_3') # Add input slot self.data.add_input('input_4') # Add input slot self.data.add_output('output') self.table = TableView() self.table.setModel(self.data.o['output'].as_table) self.views.addView(self.table, 'Table', unfocus_on_refresh=True) # Setup data consumer options self.data.consumer_defs.extend([ DataDefinition('input_1', { 'entities_t': (None, ['Compound', 'Gene', 'Protein']), }, title='Source compound, gene or protein data'), DataDefinition('input_2', { 'entities_t': (None, ['Compound', 'Gene', 'Protein']), }, title='Source compound, gene or protein data'), DataDefinition('input_3', { 'entities_t': (None, ['Compound', 'Gene', 'Protein']), }, title='Source compound, gene or protein data'), DataDefinition('input_4', { 'entities_t': (None, ['Compound', 'Gene', 'Protein']), }, title='Source compound, gene or protein data'), ]) self.addConfigPanel(PathwayMiningConfigPanel, 'Pathway Mining') self.finalise() def generate(self, input_1=None, input_2=None, input_3=None, input_4=None): #dsi = input # Iterate all the compounds in the current analysis # Assign score to each of the compound's pathways # Sum up, crop and return a list of pathway_ids to display # Pass this in as the list to view # + requested pathways, - excluded pathways db = self.m.db mining_depth = self.config.get('/Data/MiningDepth') mining_type = self.config.get('/Data/MiningType') pathway_scores = defaultdict(int) for dsi in input_1, input_2, input_3, input_4: if dsi == None: continue print("Mining using '%s'" % mining_type) for n, entity in enumerate(dsi.entities[1]): if entity == None: continue # Skip score = dsi.data[0, n] #score = self.analysis[ m_id ]['score'] # 1' neighbours; 2' neighbours etc. add score # Get a list of methods in connected reactions, add their score % to this compound # if m_id in db.compounds.keys(): # n_compounds = [r.compounds for r in db.compounds[ m_id ].reactions ] # print n_compounds # n_compounds = [m for ml in n_compounds for m in ml if n_m.id in self.analysis and m.id != m_id ] # for n_m in n_compounds: # score += self.analysis[ n_m.id ]['score'] * 0.5 # Get the entity's pathways pathways = entity.pathways if pathways == []: continue if self.config.get('/Data/MiningShared'): # Share the change score between the associated pathways # this prevents compounds having undue influence score = score / len(pathways) for p in pathways: mining_val = { 'c': abs(score), 'u': max(0, score), 'd': abs(min(0, score)), 'm': 1.0, 't': score, } pathway_scores[p] += mining_val[mining_type] # If we're using tendency scaling; abs the scores here if mining_type == 't': for p, v in list(pathway_scores.items()): pathway_scores[p] = abs(v) # If we're pruning, then remove any pathways not in keep_pathways if self.config.get('/Data/MiningRelative'): print("Scaling pathway scores to pathway sizes...") for p, v in list(pathway_scores.items()): pathway_scores[p] = float(v) / len(p.reactions) if not pathway_scores: # No data raise BaseException # Now take the accumulated scores; and create the output pathway_scorest = list(pathway_scores.items()) # Switch it to a dict so we can sort pathway_scorest = [(p, v) for p, v in pathway_scorest if v > 0] # Remove any scores of 0 pathway_scorest.sort(key=lambda tup: tup[1], reverse=True) # Sort by scores (either system) # Get top N defined by mining_depth parameter keep_pathways = pathway_scorest[0:mining_depth] remaining_pathways = pathway_scorest[mining_depth + 1:mining_depth + 100] print("Mining recommended %d out of %d" % (len(keep_pathways), len(pathway_scores))) for n, p in enumerate(keep_pathways): print("- %d. %s [%.2f]" % (n + 1, p[0].name, p[1])) #self.analysis['mining_ranked_remaining_pathways'] = [] #if remaining_pathways: # print "Note: Next pathways by current scoring method are..." # for n2,p in enumerate(remaining_pathways): # print "- %d. %s [%.2f]" % (n+n2+1, db.pathways[ p[0] ].name, p[1]) # self.analysis['mining_ranked_remaining_pathways'].append( p[0] ) #self.analysis_suggested_pathways = [db.pathways[p[0]] for p in pathway_scorest] dso = DataSet(size=(1, len(keep_pathways))) dso.entities[1] = [k for k, v in keep_pathways] dso.labels[1] = [k.name for k, v in keep_pathways] dso.data = np.array([v for k, v in keep_pathways], ndmin=2) dso.labels[0][0] = "Pathway mining scores" return {'output': dso} def onMiningSettings(self): """ Open the mining setup dialog to define conditions, ranges, class-comparisons, etc. """ dialog = dialogMiningSettings(parent=self) ok = dialog.exec_() if ok: self.config.set('/Data/MiningDepth', dialog.sb_miningDepth.value()) self.config.set('/Data/MiningType', METAPATH_MINING_TYPE_CODE[dialog.cb_miningType.currentIndex()]) self.config.set('/Data/MiningRelative', dialog.xb_miningRelative.isChecked()) self.config.set('/Data/MiningShared', dialog.xb_miningShared.isChecked()) # Update the toolbar dropdown to match self.sb_miningDepth.setValue(dialog.sb_miningDepth.value()) def onModifyMiningDepth(self): """ Change mine depth via toolbar spinner """ self.config.set('/Data/MiningDepth', self.sb_miningDepth.value()) def onDefineExperiment(self): """ Open the experimental setup dialog to define conditions, ranges, class-comparisons, etc. """ dialog = dialogDefineExperiment(parent=self) ok = dialog.exec_() if ok: # Regenerate the graph view self.config.set('experiment_control', dialog.cb_control.currentText()) self.config.set('experiment_test', dialog.cb_test.currentText()) # Update toolbar to match any change caused by timecourse settings self.update_view_callback_enabled = False # Disable to stop multiple refresh as updating the list self.cb_control.clear() self.cb_test.clear() self.cb_control.addItems([dialog.cb_control.itemText(i) for i in range(dialog.cb_control.count())]) self.cb_test.addItems([dialog.cb_test.itemText(i) for i in range(dialog.cb_test.count())])
class MapEntityApp(ui.GenericApp): def __init__(self, **kwargs): super(MapEntityApp, self).__init__(**kwargs) # Define automatic mapping (settings will determine the route; allow manual tweaks later) self.addDataToolBar() self.addFigureToolBar() self.data.add_input('input') # Add input slot self.data.add_output('output') self.table = TableView() self.table.setItemDelegate(EntityItemDelegate()) self.data.o['output'].register_interface('as_entity_table', EntityTableInterface) self.views.addView(self.table, 'Table', unfocus_on_refresh=True) self.table.setModel(self.data.o['output'].as_entity_table) # Deprecate as too slow for large mappings #self.views.addTab(WheezyView(self), 'Entities') t = self.getCreatedToolbar('Entity mapping', 'external-data') import_dataAction = QAction( QIcon(os.path.join(utils.scriptdir, 'icons', 'disk--arrow.png')), 'Load annotations from file\\u2026', self.m) import_dataAction.setStatusTip('Load annotations from .csv. file') import_dataAction.triggered.connect(self.onImportEntities) t.addAction(import_dataAction) self.addExternalDataToolbar() # Add standard source data options self.config.set_defaults({ 'map_object_type': MAP_ENTITY_ALL, }) self._entity_mapping_table = {} # Setup data consumer options self.data.consumer_defs.append( DataDefinition('input', { 'labels_n': (None, '>0'), 'entities_t': (None, None), })) self.addConfigPanel(MapEntityConfigPanel, 'Mapping') self.finalise() def onImportEntities(self): """ Open a data file""" filename, _ = QFileDialog.getOpenFileName( self.m, 'Load entity mapping from file', 'Load CSV mapping for name <> identity', "All compatible files (*.csv);;Comma Separated Values (*.csv);;All files (*.*)" ) if filename: self.load_datafile(filename) def load_datafile(self, filename): self._entity_mapping_table = {} # Load metabolite entities mapping from file (csv) reader = UnicodeReader(open(filename, 'rU'), delimiter=',', dialect='excel') # Read each row in turn, build link between items on a row (multiway map) # If either can find an entity (via synonyms; make the link) for row in reader: for s in row: if s in self.m.db.index: e = self.m.db.index[s] break else: continue # next row if we find nothing # break to here if we do for s in row: self._entity_mapping_table[s] = e self.generate() def generate(self, input=None): dso = self.translate(input, self.m.db) return {'output': dso} ###### TRANSLATION to METACYC IDENTIFIERS def translate(self, data, db): lku = { MAP_ENTITY_ALL: db.synrev, MAP_ENTITY_GENE: db.synrev_by_type['gene'], MAP_ENTITY_PROTEIN: db.synrev_by_type['protein'], MAP_ENTITY_COMPOUND: db.synrev_by_type['compound'], }[self.config.get('map_object_type')] # Translate loaded data names to metabolite IDs using provided database for lookup for n, m in enumerate(data.labels[1]): # Match first using entity mapping table if set (allows override of defaults) if m in self._entity_mapping_table: data.entities[1][n] = self._entity_mapping_table[m] # Use the internal database identities elif m and m.lower() in lku: data.entities[1][n] = lku[m.lower()] #self.quantities[ transid ] = self.quantities.pop( m ) #print self.metabolites return data
class MapEntityApp(ui.GenericApp): def __init__(self, **kwargs): super(MapEntityApp, self).__init__(**kwargs) # Define automatic mapping (settings will determine the route; allow manual tweaks later) self.addDataToolBar() self.addFigureToolBar() self.data.add_input('input') # Add input slot self.data.add_output('output') self.table = TableView() self.table.setItemDelegate(EntityItemDelegate()) self.data.o['output'].register_interface('as_entity_table', EntityTableInterface) self.views.addView(self.table, 'Table', unfocus_on_refresh=True) self.table.setModel(self.data.o['output'].as_entity_table) # Deprecate as too slow for large mappings #self.views.addTab(WheezyView(self), 'Entities') t = self.getCreatedToolbar('Entity mapping', 'external-data') import_dataAction = QAction(QIcon(os.path.join(utils.scriptdir, 'icons', 'disk--arrow.png')), 'Load annotations from file\\u2026', self.m) import_dataAction.setStatusTip('Load annotations from .csv. file') import_dataAction.triggered.connect(self.onImportEntities) t.addAction(import_dataAction) self.addExternalDataToolbar() # Add standard source data options self.config.set_defaults({ 'map_object_type': MAP_ENTITY_ALL, }) self._entity_mapping_table = {} # Setup data consumer options self.data.consumer_defs.append( DataDefinition('input', { 'labels_n': (None, '>0'), 'entities_t': (None, None), }) ) self.addConfigPanel(MapEntityConfigPanel, 'Mapping') self.finalise() def onImportEntities(self): """ Open a data file""" filename, _ = QFileDialog.getOpenFileName(self.m, 'Load entity mapping from file', 'Load CSV mapping for name <> identity', "All compatible files (*.csv);;Comma Separated Values (*.csv);;All files (*.*)") if filename: self.load_datafile(filename) def load_datafile(self, filename): self._entity_mapping_table = {} # Load metabolite entities mapping from file (csv) reader = UnicodeReader(open(filename, 'rU'), delimiter=',', dialect='excel') # Read each row in turn, build link between items on a row (multiway map) # If either can find an entity (via synonyms; make the link) for row in reader: for s in row: if s in self.m.db.index: e = self.m.db.index[s] break else: continue # next row if we find nothing # break to here if we do for s in row: self._entity_mapping_table[s] = e self.generate() def generate(self, input=None): dso = self.translate(input, self.m.db) return {'output': dso} ###### TRANSLATION to METACYC IDENTIFIERS def translate(self, data, db): lku = { MAP_ENTITY_ALL: db.synrev, MAP_ENTITY_GENE: db.synrev_by_type['gene'], MAP_ENTITY_PROTEIN: db.synrev_by_type['protein'], MAP_ENTITY_COMPOUND: db.synrev_by_type['compound'], }[self.config.get('map_object_type')] # Translate loaded data names to metabolite IDs using provided database for lookup for n, m in enumerate(data.labels[1]): # Match first using entity mapping table if set (allows override of defaults) if m in self._entity_mapping_table: data.entities[1][n] = self._entity_mapping_table[m] # Use the internal database identities elif m and m.lower() in lku: data.entities[1][n] = lku[m.lower()] #self.quantities[ transid ] = self.quantities.pop( m ) #print self.metabolites return data
class PathwayMiningApp(ui.AnalysisApp): def __init__(self, **kwargs): super(PathwayMiningApp, self).__init__(**kwargs) # Define automatic mapping (settings will determine the route; allow manual tweaks later) self.addDataToolBar() #self.addExperimentToolBar() self.config.set_defaults({ '/Data/MiningActive': False, '/Data/MiningDepth': 5, '/Data/MiningType': 'c', '/Data/MiningRelative': False, '/Data/MiningShared': True, }) #t = self.getCreatedToolbar('Pathway mining', 'pathway_mining') #miningSetup = QAction( QIcon( os.path.join( self.plugin.path, 'icon-16.png' ) ), 'Set up pathway mining \u2026', self.m) #miningSetup.setStatusTip('Set parameters for pathway mining') #miningSetup.triggered.connect(self.onMiningSettings) #t.addAction(miningSetup) self.data.add_input('input_1') # Add input slot self.data.add_input('input_2') # Add input slot self.data.add_input('input_3') # Add input slot self.data.add_input('input_4') # Add input slot self.data.add_output('output') self.table = TableView() self.table.setModel(self.data.o['output'].as_table) self.views.addView(self.table, 'Table', unfocus_on_refresh=True) # Setup data consumer options self.data.consumer_defs.extend([ DataDefinition('input_1', { 'entities_t': (None, ['Compound', 'Gene', 'Protein']), }, title='Source compound, gene or protein data'), DataDefinition('input_2', { 'entities_t': (None, ['Compound', 'Gene', 'Protein']), }, title='Source compound, gene or protein data'), DataDefinition('input_3', { 'entities_t': (None, ['Compound', 'Gene', 'Protein']), }, title='Source compound, gene or protein data'), DataDefinition('input_4', { 'entities_t': (None, ['Compound', 'Gene', 'Protein']), }, title='Source compound, gene or protein data'), ]) self.addConfigPanel(PathwayMiningConfigPanel, 'Pathway Mining') self.finalise() def generate(self, input_1=None, input_2=None, input_3=None, input_4=None): #dsi = input # Iterate all the compounds in the current analysis # Assign score to each of the compound's pathways # Sum up, crop and return a list of pathway_ids to display # Pass this in as the list to view # + requested pathways, - excluded pathways db = self.m.db mining_depth = self.config.get('/Data/MiningDepth') mining_type = self.config.get('/Data/MiningType') pathway_scores = defaultdict(int) for dsi in input_1, input_2, input_3, input_4: if dsi == None: continue print("Mining using '%s'" % mining_type) for n, entity in enumerate(dsi.entities[1]): if entity == None: continue # Skip score = dsi.data[0, n] #score = self.analysis[ m_id ]['score'] # 1' neighbours; 2' neighbours etc. add score # Get a list of methods in connected reactions, add their score % to this compound # if m_id in db.compounds.keys(): # n_compounds = [r.compounds for r in db.compounds[ m_id ].reactions ] # print n_compounds # n_compounds = [m for ml in n_compounds for m in ml if n_m.id in self.analysis and m.id != m_id ] # for n_m in n_compounds: # score += self.analysis[ n_m.id ]['score'] * 0.5 # Get the entity's pathways pathways = entity.pathways if pathways == []: continue if self.config.get('/Data/MiningShared'): # Share the change score between the associated pathways # this prevents compounds having undue influence score = score / len(pathways) for p in pathways: mining_val = { 'c': abs(score), 'u': max(0, score), 'd': abs(min(0, score)), 'm': 1.0, 't': score, } pathway_scores[p] += mining_val[mining_type] # If we're using tendency scaling; abs the scores here if mining_type == 't': for p, v in list(pathway_scores.items()): pathway_scores[p] = abs(v) # If we're pruning, then remove any pathways not in keep_pathways if self.config.get('/Data/MiningRelative'): print("Scaling pathway scores to pathway sizes...") for p, v in list(pathway_scores.items()): pathway_scores[p] = float(v) / len(p.reactions) if not pathway_scores: # No data raise BaseException # Now take the accumulated scores; and create the output pathway_scorest = list( pathway_scores.items()) # Switch it to a dict so we can sort pathway_scorest = [(p, v) for p, v in pathway_scorest if v > 0] # Remove any scores of 0 pathway_scorest.sort(key=lambda tup: tup[1], reverse=True) # Sort by scores (either system) # Get top N defined by mining_depth parameter keep_pathways = pathway_scorest[0:mining_depth] remaining_pathways = pathway_scorest[mining_depth + 1:mining_depth + 100] print("Mining recommended %d out of %d" % (len(keep_pathways), len(pathway_scores))) for n, p in enumerate(keep_pathways): print("- %d. %s [%.2f]" % (n + 1, p[0].name, p[1])) #self.analysis['mining_ranked_remaining_pathways'] = [] #if remaining_pathways: # print "Note: Next pathways by current scoring method are..." # for n2,p in enumerate(remaining_pathways): # print "- %d. %s [%.2f]" % (n+n2+1, db.pathways[ p[0] ].name, p[1]) # self.analysis['mining_ranked_remaining_pathways'].append( p[0] ) #self.analysis_suggested_pathways = [db.pathways[p[0]] for p in pathway_scorest] dso = DataSet(size=(1, len(keep_pathways))) dso.entities[1] = [k for k, v in keep_pathways] dso.labels[1] = [k.name for k, v in keep_pathways] dso.data = np.array([v for k, v in keep_pathways], ndmin=2) dso.labels[0][0] = "Pathway mining scores" return {'output': dso} def onMiningSettings(self): """ Open the mining setup dialog to define conditions, ranges, class-comparisons, etc. """ dialog = dialogMiningSettings(parent=self) ok = dialog.exec_() if ok: self.config.set('/Data/MiningDepth', dialog.sb_miningDepth.value()) self.config.set( '/Data/MiningType', METAPATH_MINING_TYPE_CODE[dialog.cb_miningType.currentIndex()]) self.config.set('/Data/MiningRelative', dialog.xb_miningRelative.isChecked()) self.config.set('/Data/MiningShared', dialog.xb_miningShared.isChecked()) # Update the toolbar dropdown to match self.sb_miningDepth.setValue(dialog.sb_miningDepth.value()) def onModifyMiningDepth(self): """ Change mine depth via toolbar spinner """ self.config.set('/Data/MiningDepth', self.sb_miningDepth.value()) def onDefineExperiment(self): """ Open the experimental setup dialog to define conditions, ranges, class-comparisons, etc. """ dialog = dialogDefineExperiment(parent=self) ok = dialog.exec_() if ok: # Regenerate the graph view self.config.set('experiment_control', dialog.cb_control.currentText()) self.config.set('experiment_test', dialog.cb_test.currentText()) # Update toolbar to match any change caused by timecourse settings self.update_view_callback_enabled = False # Disable to stop multiple refresh as updating the list self.cb_control.clear() self.cb_test.clear() self.cb_control.addItems([ dialog.cb_control.itemText(i) for i in range(dialog.cb_control.count()) ]) self.cb_test.addItems([ dialog.cb_test.itemText(i) for i in range(dialog.cb_test.count()) ])