diff --git a/Docs/ChangeLog.md b/Docs/ChangeLog.md index a565514..3987e5d 100644 --- a/Docs/ChangeLog.md +++ b/Docs/ChangeLog.md @@ -1,8 +1,7 @@ -# Version: 1.116.1 -## Date: 2024-10-28 +# Version: 1.117.0 +## Date: 2024-10-31 ### Changes: -- Fix: Fixed the bug of when plot the heatmap of taxa-funcs with t-ststistic and f-statistic, the value still selected as p-value. -- Change: Updated the cookbook. +- New: added result Table after plotting the network of Taxa-Functions and Co-Expression. # Version: 1.116.0 ## Date: 2024-10-18 diff --git a/metax/gui/main_gui.py b/metax/gui/main_gui.py index 5feea8c..75ff53e 100644 --- a/metax/gui/main_gui.py +++ b/metax/gui/main_gui.py @@ -5170,15 +5170,19 @@ def plot_co_expr(self, plot_type = 'network'): elif plot_type == 'network': try: self.show_message('Co-expression network is plotting...\n\n It may take a long time! Please wait...') - pic = NetworkPlot(self.tfa, + pic, corr_df = NetworkPlot(self.tfa, show_labels=show_labels, rename_taxa=rename_taxa, font_size=font_size, theme=self.html_theme, **self.tf_link_net_params_dict ).plot_co_expression_network(df_type= df_type, corr_method=corr_method, - corr_threshold=corr_threshold, sample_list=sample_list, width=width, height=height, focus_list=focus_list, plot_list_only=plot_list_only) + corr_threshold=corr_threshold, sample_list=sample_list, + width=width, height=height, focus_list=focus_list, + plot_list_only=plot_list_only) self.save_and_show_js_plot(pic, 'co-expression network') + self.update_table_dict(f'co-expression_network({df_type})', corr_df) + except ValueError as e: if 'sample_list should have at least 2' in str(e): QMessageBox.warning(self.MainWindow, 'Error', "At least 2 samples are required!") @@ -5409,7 +5413,7 @@ def plot_network(self): try: self.show_message('Plotting network...') list_only_no_link = self.checkBox_tf_link_net_plot_list_only_no_link.isChecked() - pic = NetworkPlot( + pic, network_df = NetworkPlot( self.tfa, show_labels=show_labels, rename_taxa=rename_taxa, @@ -5425,6 +5429,8 @@ def plot_network(self): list_only_no_link=list_only_no_link, ) self.save_and_show_js_plot(pic, 'taxa-func link Network') + self.update_table_dict('taxa-func_network', network_df) + except Exception as e: error_message = traceback.format_exc() self.logger.write_log(f'plot_network error: {error_message}', 'e') diff --git a/metax/taxafunc_ploter/network_plot.py b/metax/taxafunc_ploter/network_plot.py index 655930d..beae9a2 100644 --- a/metax/taxafunc_ploter/network_plot.py +++ b/metax/taxafunc_ploter/network_plot.py @@ -1,6 +1,8 @@ from pyecharts import options as opts from pyecharts.charts import Graph import pandas as pd +import numpy as np +from typing import Tuple class NetworkPlot: def __init__(self, tfobj, @@ -60,7 +62,7 @@ def __init__(self, tfobj, self.show_sub_title = show_sub_title - def modify_focus_list(self, focus_list): + def modify_focus_list(self, focus_list, return_taxa_functions_separately = True): ''' Split the taxa-func item into taxa and function if it's in the focus_list ''' @@ -71,8 +73,12 @@ def modify_focus_list(self, focus_list): taxa = i.split(' <')[0].split('|')[-1] func = i.split(' <')[1][:-1] # i = taxa.split('|')[-1] + ' <' + func + '>' - new_focus_list.append(taxa) - new_focus_list.append(func) + if return_taxa_functions_separately: + new_focus_list.append(taxa) + new_focus_list.append(func) + else: + taxa_func = taxa + ' <' + func + '>' + new_focus_list.append(taxa_func) else: # taxa item i = i.split('|')[-1] new_focus_list.append(i) @@ -99,12 +105,13 @@ def create_nodes_links( - sample_list (list, optional): Specifies which samples to include. If None, all samples are used. - focus_list (list, optional): List of taxa and functions to highlight in the network. - plot_list_only (bool, optional): If True, only items and theri linked items in focus_list are plotted. - - strict_list (bool, optional): If True, only items in focus_list are plotted. + - list_only_no_link (bool, optional): If True, only items in focus_list are plotted, not including the links of the focus items. Returns: - nodes (list): Information about each node for the graph, including name and size. - links (list): Information about links between nodes. - categories (list): Categories for nodes, used for coloring in the graph. + - cytoscape_df (DataFrame): DataFrame containing nodes and links for Cytoscape export. """ df = self.tfa.taxa_func_df.copy() if self.rename_taxa: @@ -120,6 +127,16 @@ def create_nodes_links( print("No sample list provided, using all samples") df = df.loc[~(df==0).all(axis=1)] + + # create network_df for export to cytoscape + network_df = self.tfa.BasicStats.get_stats_mean_df_by_group(df) + network_df['sum'] = network_df.sum(axis=1) + network_df.reset_index(inplace=True) + network_df.columns = ['taxa', 'function'] + network_df.columns.tolist()[2:] + network_df['focus_taxa'] = network_df['taxa'].apply(lambda x: 'Y' if x in focus_list else 'N') + network_df['focus_func'] = network_df['function'].apply(lambda x: 'Y' if x in focus_list else 'N') + # Done creating network_df + df['sum'] = df.sum(axis=1) df.reset_index(inplace=True) colname = df.columns.tolist() @@ -143,8 +160,7 @@ def create_nodes_links( df_func['taxa'] = "" # concatenate the uncovered taxa and functions df = pd.concat([df_coverd, df_taxa, df_func]) - - + else: df = df.loc[df['taxa'].isin(focus_list) | df['function'].isin(focus_list)] print(f"New df shape: {df.shape}") @@ -190,7 +206,6 @@ def normalize(value): {"name": "Focus_Function", "itemStyle": {"normal": {"color": self.func_focus_color}}}, ] - return nodes, links, categories else: nodes = [{"name": taxon, "category": 0, "symbolSize": normalize(taxa_sum[taxon]), "value": taxa_sum[taxon], "symbol": self.taxa_shape} for taxon in taxa] + \ @@ -202,7 +217,7 @@ def normalize(value): {"name": "Function", "itemStyle": {"normal": {"color": self.func_color}}}, ] - return nodes, links, categories + return nodes, links, categories, network_df def plot_tflink_network( self, @@ -212,7 +227,7 @@ def plot_tflink_network( focus_list: list = None, plot_list_only: bool = False, list_only_no_link: bool = False, - ): + ) -> Tuple[Graph, pd.DataFrame]: """ Creates a network graph of taxa and functions using Pyecharts. @@ -224,10 +239,11 @@ def plot_tflink_network( - height (int, optional): Height of the graph in pixels. - focus_list (list, optional): List of taxa and functions to highlight. - plot_list_only (bool, optional): If True, only plots items in focus_list and their linked items. - - strict_list_only (bool, optional): If True, only plots items in focus_list. + - list_only_no_link (bool, optional): If True, only plots items in focus_list, not including the links of the focus items. Returns: - A Pyecharts Graph object that can be displayed in Jupyter notebooks or web pages. + - A DataFrame containing nodes and links for export to Cytoscape. """ # preprocess focus_list @@ -244,10 +260,13 @@ def plot_tflink_network( new_list.extend((taxon, func)) else: print(f"Warning: {i} is not in taxa or function list") - nodes, links, categories = self.create_nodes_links(sample_list, new_list,plot_list_only, list_only_no_link) + nodes, links, categories, network_df = self.create_nodes_links(sample_list=sample_list, + focus_list = new_list, + plot_list_only = plot_list_only, + list_only_no_link=list_only_no_link) else: focus_list = [] - nodes, links, categories = self.create_nodes_links(sample_list) + nodes, links, categories, network_df = self.create_nodes_links(sample_list = sample_list) c = ( @@ -317,13 +336,20 @@ def plot_tflink_network( ) - return c + return c , network_df def plot_co_expression_network(self, df_type:str= 'taxa', corr_method:str = 'pearson', corr_threshold:float=0.5, sample_list:list[str]|None = None, width:int = 12, height:int = 8, focus_list:list[str] = [], plot_list_only:bool = False, - ): + ) -> Tuple[Graph, pd.DataFrame]: + """ + Plots a co-expression network based on the correlation matrix of the specified data type. + Returns: + -------- + Tuple[Graph, pd.DataFrame] + A tuple containing the network plot (Graph) and the network data frame (pd.DataFrame). + """ from matplotlib import colormaps #check sample_list length if sample_list and len(sample_list) < 2: @@ -341,7 +367,7 @@ def plot_co_expression_network(self, df_type:str= 'taxa', corr_method:str = 'pea print("Renaming taxa to last level") df = self.tfa.rename_taxa(df) # modify the focus_list to the last level taxa - focus_list = self.modify_focus_list(focus_list) + focus_list = self.modify_focus_list(focus_list, return_taxa_functions_separately=False) if extra_cols := sample_list: print(f"Using sample list provided {extra_cols}") @@ -358,6 +384,18 @@ def plot_co_expression_network(self, df_type:str= 'taxa', corr_method:str = 'pea correlation_matrix = df.corr(method='spearman') else: raise ValueError(f"corr_method should be pearson or spearman, but got {corr_method}") + + # cerate network_df for export to cytoscape from the correlation matrix + mask = np.triu(np.ones(correlation_matrix.shape), k=1).astype(bool) + network_df = network_df = correlation_matrix.where(mask) + # set index name and header name as item1 and item2 + network_df.index.name = f'{df_type}1' + network_df.columns.name = f'{df_type}2' + network_df = network_df.stack().reset_index() + network_df.columns = [ f'{df_type}1', f'{df_type}2', 'correlation'] + network_df['item1_focus'] = network_df[f'{df_type}1'].apply(lambda x: 'Y' if x in focus_list else 'N') + network_df['item2_focus'] = network_df[f'{df_type}2'].apply(lambda x: 'Y' if x in focus_list else 'N') + # Done creating network_df node_sizes = correlation_matrix.apply(lambda x: (x > corr_threshold).sum(), axis=1) max_node_size = node_sizes.max() @@ -491,7 +529,7 @@ def plot_co_expression_network(self, df_type:str= 'taxa', corr_method:str = 'pea ), ) ) - return pic + return pic, network_df diff --git a/metax/utils/version.py b/metax/utils/version.py index d936c4f..ca0218e 100644 --- a/metax/utils/version.py +++ b/metax/utils/version.py @@ -1,2 +1,2 @@ -__version__ = '1.116.1' +__version__ = '1.117.0' API_version = '3' \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 209f360..6791e77 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "MetaXTools" -version = "1.116.1" +version = "1.117.0" description = "MetaXTools is a novel tool for linking peptide sequences with taxonomic and functional information in Metaproteomics." readme = "README_PyPi.md" license = { text = "NorthOmics" }