From 0ff26262a29b86002853371487116fd342cc3201 Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Sun, 12 Mar 2023 19:41:56 +0100 Subject: [PATCH 01/17] multicova analsis --- alphastats/DataSet_Statistics.py | 32 ++++++++++++ alphastats/statistics/MultiCovaAnalysis.py | 58 ++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 alphastats/statistics/MultiCovaAnalysis.py diff --git a/alphastats/DataSet_Statistics.py b/alphastats/DataSet_Statistics.py index 8bf0f76b..00fd638a 100644 --- a/alphastats/DataSet_Statistics.py +++ b/alphastats/DataSet_Statistics.py @@ -7,6 +7,7 @@ from alphastats.utils import ignore_warning from tqdm import tqdm from functools import lru_cache +from alphastats.statistics.MultiCovaAnalysis import MultiCovaAnalysis class Statistics: @@ -319,3 +320,34 @@ def ancova(self, protein_id, covar, between): df = self.metadata.merge(df, how="inner", on=[self.sample]) ancova_df = pingouin.ancova(df, dv=protein_id, covar=covar, between=between) return ancova_df + + def multi_covariat_analysis( + self, + covariates:list, + n_permutations=3, + fdr=0.05, + s0=0.05, + subset:dict + ): + """Multicovarait Analysis + + Args: + covariates (list): List of covariates, column names in metadata + subset (dict): _description_ + n_permutations (int, optional): _description_. Defaults to 3. + fdr (float, optional): _description_. Defaults to 0.05. + s0 (float, optional): _description_. Defaults to 0.05. + + Returns: + _type_: _description_ + """ + res = MultiCovaAnalysis( + dataset=self, + covariates=covariates, + n_permutations=n_permutations, + fdr=fdr, + s0=s0, + subset=subset + ).calculate() + return res + diff --git a/alphastats/statistics/MultiCovaAnalysis.py b/alphastats/statistics/MultiCovaAnalysis.py new file mode 100644 index 00000000..fa953c11 --- /dev/null +++ b/alphastats/statistics/MultiCovaAnalysis.py @@ -0,0 +1,58 @@ + + +class MultiCovaAnalysis: + def __init__(self, dataset,covariates, n_permutations=3, fdr=0.05, s0=0.05, subset=None): + self.dataset = dataset + self.covariates = covariates + self.n_permutatons = n_permutations + self.fdr = fdr + self.s0 = s0 + self.subset = subset + + if len(self.covariates) == 0: + print("Covariates are invalid for analysis.") + return + + def _subset_metadata(self): + if self.subset is not None: + # dict structure {"column_name": ["group1", "group2"]} + subset_column = list(self.subset.keys())[0] + groups = self.subset.get(subset_column) + self.metadata = self.dataset.metadata[self.dataset.metadata[subset_column].isin(groups)] + + else: + self.metadata = self.dataset.metadata + + def _check_covariat_input(self): + # check whether covariates in metadata column + misc_covariates = list(set(self.metadata.columns.to_list()) - set(self.covariates)) + if len(misc_covariates)> 0: + Warning(f"Covariates: {misc_covariates} are not found in Metadata.") + self.covariates = filter(lambda i: i not in misc_covariates, self.covariates) + + + def _check_na_values(self): + for covariate in self.covariates: + if metadata[covariate].isna().any(): + self.covariates.remove(covariate) + Warning(f"Covariate: {covariate} contains missing values" + + f"in metadata and will not be used for analysis.") + + def _prepare_matrix(self): + transposed = self.dataset.mat.transpose() + transposed[self.dataset.index_column] = transposed.index + transposed = transposed.reset_index(drop=True) + self.transposed = transposed[self.metadata[self.dataset.sample].to_list()] + + def calculate(self): + from alphastats.multicova import multicova + res, tlim = multicova.full_regression_analysis( + quant_data = self.transposed, + annotation = self.metadata, + covariates = self.covariates, + sample_column = self.sample, + n_permutations=self.n_permutations, + fdr=self.fdr, + s0=self.s0 + ) + return res \ No newline at end of file From 1c75ba200bbefa9d710cbff1f2bb966a9ed9dd63 Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Mon, 13 Mar 2023 16:45:29 +0100 Subject: [PATCH 02/17] add types to parameters --- alphastats/DataSet_Plot.py | 91 +++++++++++++++++++------------- alphastats/DataSet_Preprocess.py | 45 ++++++++-------- alphastats/DataSet_Statistics.py | 88 +++++++++++++++++------------- 3 files changed, 130 insertions(+), 94 deletions(-) diff --git a/alphastats/DataSet_Plot.py b/alphastats/DataSet_Plot.py index 9933ddb9..1e16ca5b 100644 --- a/alphastats/DataSet_Plot.py +++ b/alphastats/DataSet_Plot.py @@ -13,6 +13,7 @@ import random import itertools import plotly.figure_factory +from typing import Union from alphastats.plots.DimensionalityReduction import DimensionalityReduction from alphastats.plots.VolcanoPlot import VolcanoPlot @@ -53,6 +54,7 @@ class seaborn_object(sns.matrix.ClusterGrid): plotly.io.templates.default = "simple_white+alphastats_colors" + class Plot: def _update_figure_attributes(self, figure_object, plotting_data, method=None): setattr(figure_object, "plotting_data", plotting_data) @@ -61,7 +63,7 @@ def _update_figure_attributes(self, figure_object, plotting_data, method=None): return figure_object @check_for_missing_values - def plot_pca(self, group=None, circle=False): + def plot_pca(self, group: str = None, circle: bool = False): """Plot Principal Component Analysis (PCA) Args: @@ -76,9 +78,14 @@ def plot_pca(self, group=None, circle=False): ) return dimensionality_reduction.plot - @check_for_missing_values - def plot_tsne(self, group=None, circle=False, perplexity=5, n_iter=1000): + def plot_tsne( + self, + group: str = None, + circle: bool = False, + perplexity: int = 5, + n_iter: int = 1000, + ): """Plot t-distributed stochastic neighbor embedding (t-SNE) Args: @@ -99,7 +106,7 @@ def plot_tsne(self, group=None, circle=False, perplexity=5, n_iter=1000): return dimensionality_reduction.plot @check_for_missing_values - def plot_umap(self, group=None, circle=False): + def plot_umap(self, group: str = None, circle: bool = False): """Plot Uniform Manifold Approximation and Projection for Dimension Reduction Args: @@ -116,17 +123,17 @@ def plot_umap(self, group=None, circle=False): def plot_volcano( self, - group1, - group2, - column=None, - method="ttest", - labels=False, - min_fc=1, - alpha=0.05, - draw_line=True, - perm=100, - fdr=0.05, - compare_preprocessing_modes=False + group1: Union[str, list], + group2: Union[str, list], + column: str = None, + method: str = "ttest", + labels: bool = False, + min_fc: float = 1.0, + alpha: float = 0.05, + draw_line: bool = True, + perm: int = 100, + fdr: float = 0.05, + compare_preprocessing_modes: bool = False, ): """Plot Volcano Plot @@ -150,9 +157,11 @@ def plot_volcano( if compare_preprocessing_modes: params_for_func = locals() - results = self._compare_preprocessing_modes(func=VolcanoPlot,params_for_func=params_for_func) + results = self._compare_preprocessing_modes( + func=VolcanoPlot, params_for_func=params_for_func + ) return results - + else: volcano_plot = VolcanoPlot( dataset=self, @@ -164,13 +173,13 @@ def plot_volcano( min_fc=min_fc, alpha=alpha, draw_line=draw_line, - perm=perm, - fdr=fdr + perm=perm, + fdr=fdr, ) return volcano_plot.plot - def plot_correlation_matrix(self, method="pearson"): + def plot_correlation_matrix(self, method: str = "pearson"): """Plot Correlation Matrix Args: @@ -184,7 +193,9 @@ def plot_correlation_matrix(self, method="pearson"): plot = px.imshow(corr_matrix) return plot - def plot_sampledistribution(self, method="violin", color=None, log_scale=False): + def plot_sampledistribution( + self, method: str = "violin", color: bool = None, log_scale: bool = False + ): """Plot Intensity Distribution for each sample. Either Violin or Boxplot Args: @@ -226,18 +237,18 @@ def plot_sampledistribution(self, method="violin", color=None, log_scale=False): def plot_intensity( self, - protein_id, - group=None, - subgroups=None, - method="box", - add_significance=False, - log_scale=False, - compare_preprocessing_modes=False + protein_id: str, + group: str = None, + subgroups: list = None, + method: str = "box", + add_significance: bool = False, + log_scale: bool = False, + compare_preprocessing_modes: bool = False, ): """Plot Intensity of individual Protein/ProteinGroup Args: - ID (str): ProteinGroup ID + protein_id (str): ProteinGroup ID group (str, optional): A metadata column used for grouping. Defaults to None. subgroups (list, optional): Select variables from the group column. Defaults to None. method (str, optional): Violinplot = "violin", Boxplot = "box", Scatterplot = "scatter". Defaults to "box". @@ -249,17 +260,19 @@ def plot_intensity( """ if compare_preprocessing_modes: params_for_func = locals() - results = self._compare_preprocessing_modes(func=IntensityPlot,params_for_func=params_for_func) + results = self._compare_preprocessing_modes( + func=IntensityPlot, params_for_func=params_for_func + ) return results - + intensity_plot = IntensityPlot( - dataset = self, + dataset=self, protein_id=protein_id, group=group, subgroups=subgroups, method=method, add_significance=add_significance, - log_scale=log_scale + log_scale=log_scale, ) return intensity_plot.plot @@ -267,7 +280,11 @@ def plot_intensity( @ignore_warning(UserWarning) @check_for_missing_values def plot_clustermap( - self, label_bar=None, only_significant=False, group=None, subgroups=None + self, + label_bar: str = None, + only_significant: bool = False, + group: str = None, + subgroups: list = None, ): """Plot a matrix dataset as a hierarchically-clustered heatmap @@ -282,13 +299,13 @@ def plot_clustermap( """ clustermap = ClusterMap( - dataset = self, + dataset=self, label_bar=label_bar, only_significant=only_significant, group=group, - subgroups=subgroups + subgroups=subgroups, ) - return clustermap.plot + return clustermap.plot @check_for_missing_values def plot_dendrogram( diff --git a/alphastats/DataSet_Preprocess.py b/alphastats/DataSet_Preprocess.py index c0a6fe4b..61993870 100644 --- a/alphastats/DataSet_Preprocess.py +++ b/alphastats/DataSet_Preprocess.py @@ -11,7 +11,7 @@ class Preprocess: - def _remove_sampels(self, sample_list): + def _remove_sampels(self, sample_list: list): # exclude samples for analysis self.mat = self.mat.drop(sample_list) self.metadata = self.metadata[~self.metadata[self.sample].isin(sample_list)] @@ -67,7 +67,7 @@ def _filter(self): @ignore_warning(RuntimeWarning) @ignore_warning(UserWarning) - def _imputation(self, method): + def _imputation(self, method: str): # remove ProteinGroups with only NA before protein_group_na = self.mat.columns[self.mat.isna().all()].tolist() @@ -128,8 +128,8 @@ def _imputation(self, method): @ignore_warning(UserWarning) @ignore_warning(RuntimeWarning) - def _normalization(self, method): - + def _normalization(self, method: str): + if method == "zscore": scaler = sklearn.preprocessing.StandardScaler() normalized_array = scaler.fit_transform(self.mat.values) @@ -162,15 +162,17 @@ def _normalization(self, method): def reset_preprocessing(self): """ Reset all preprocessing steps """ - # reset all preprocessing steps + #  reset all preprocessing steps self.create_matrix() print("All preprocessing steps are reset.") - + def _compare_preprocessing_modes(self, func, params_for_func): dataset = self imputation_methods = ["mean", "median", "knn"] normalization_methods = ["zscore", "quantile", "vst"] - preprocessing_modes = list(itertools.product(normalization_methods, imputation_methods)) + preprocessing_modes = list( + itertools.product(normalization_methods, imputation_methods) + ) results_list = [] @@ -180,33 +182,34 @@ def _compare_preprocessing_modes(self, func, params_for_func): for preprocessing_mode in preprocessing_modes: # reset preprocessing dataset.reset_preprocessing() - print(f"Normalization {preprocessing_mode[0]}, Imputation {str(preprocessing_mode[1])}") - + print( + f"Normalization {preprocessing_mode[0]}, Imputation {str(preprocessing_mode[1])}" + ) + dataset.preprocess( subset=True, - normalization = preprocessing_mode[0], - imputation = preprocessing_mode[1] + normalization=preprocessing_mode[0], + imputation=preprocessing_mode[1], ) - + res = func(**params_for_func) results_list.append(res) - + return results_list def _log2_transform(self): self.mat = np.log2(self.mat + 0.1) self.preprocessing_info.update({"Log2 Transformed": True}) - @ignore_warning(RuntimeWarning) def preprocess( self, - log2_transform=True, - remove_contaminations=False, - subset=False, - normalization=None, - imputation=None, - remove_samples=None, + log2_transform: bool = True, + remove_contaminations: bool = False, + subset: bool = False, + normalization: str = None, + imputation: str = None, + remove_samples: list = None, ): """Preprocess Protein data @@ -254,7 +257,7 @@ def preprocess( if subset: self.mat = self._subset() - + if log2_transform: self._log2_transform() diff --git a/alphastats/DataSet_Statistics.py b/alphastats/DataSet_Statistics.py index 00fd638a..a2f5c8e6 100644 --- a/alphastats/DataSet_Statistics.py +++ b/alphastats/DataSet_Statistics.py @@ -7,11 +7,12 @@ from alphastats.utils import ignore_warning from tqdm import tqdm from functools import lru_cache +from typing import Union from alphastats.statistics.MultiCovaAnalysis import MultiCovaAnalysis class Statistics: - def _add_metadata_column(self, group1_list, group2_list): + def _add_metadata_column(self, group1_list: list, group2_list: list): # create new column in metadata with defined groups metadata = self.metadata @@ -34,8 +35,9 @@ def _add_metadata_column(self, group1_list, group2_list): return column, "group1", "group2" - def _prepare_anndata(self, column, group1, group2): + def _prepare_anndata(self, column: str, group1: str, group2: str): import anndata + group_samples = self.metadata[ (self.metadata[column] == group1) | (self.metadata[column] == group2) ][self.sample].tolist() @@ -64,9 +66,16 @@ def _prepare_anndata(self, column, group1, group2): ) return anndata_data - @ignore_warning(RuntimeWarning) - def diff_expression_analysis(self, group1, group2, column=None, method="ttest", perm=10, fdr=0.05): + def diff_expression_analysis( + self, + group1: Union[str, list], + group2: Union[str, list], + column: str = None, + method: str = "ttest", + perm: int = 10, + fdr: float = 0.05, + ) -> pd.DataFrame: """Perform differential expression analysis doing a a t-test or Wald test. A wald test will fit a generalized linear model. Args: @@ -116,6 +125,7 @@ def diff_expression_analysis(self, group1, group2, column=None, method="ttest", elif method == "sam": from alphastats.multicova import multicova + transposed = self.mat.transpose() if self.preprocessing_info["Normalization"] is None: @@ -127,31 +137,35 @@ def diff_expression_analysis(self, group1, group2, column=None, method="ttest", res, _ = multicova.perform_ttest_analysis( transposed, - c1 =list(self.metadata[self.metadata[column]==group1][self.sample]), - c2 =list(self.metadata[self.metadata[column]==group2][self.sample]), - s0=0.05, + c1=list(self.metadata[self.metadata[column] == group1][self.sample]), + c2=list(self.metadata[self.metadata[column] == group2][self.sample]), + s0=0.05, n_perm=perm, fdr=fdr, id_col=self.index_column, - parallelize=True + parallelize=True, ) - fdr_column = "FDR" + str(int(fdr*100)) + "%" - df = res[[self.index_column, 'fc', 'tval', 'pval', 'tval_s0', 'pval_s0', 'qval']] + fdr_column = "FDR" + str(int(fdr * 100)) + "%" + df = res[ + [self.index_column, "fc", "tval", "pval", "tval_s0", "pval_s0", "qval"] + ] df["log2fc"] = res["fc"] df["FDR"] = res[fdr_column] - + else: raise ValueError( f"{method} is invalid choose between 'wald' for Wald-test, 'sam' and 'ttest'" ) - + if method != "sam": df = test.summary().rename(columns={"gene": self.index_column}) - + return df - def _calculate_foldchange(self, mat_transpose, group1_samples, group2_samples): + def _calculate_foldchange( + self, mat_transpose, group1_samples, group2_samples + ) -> pd.DataFrame: mat_transpose += 0.00001 fc = ( mat_transpose[group1_samples].T.mean().values @@ -165,7 +179,7 @@ def _calculate_foldchange(self, mat_transpose, group1_samples, group2_samples): return df @ignore_warning(RuntimeWarning) - def tukey_test(self, protein_id, group, df=None): + def tukey_test(self, protein_id: str, group: str, df=None) -> pd.DataFrame: """Calculate Pairwise Tukey-HSD post-hoc test Wrapper around: https://pingouin-stats.org/generated/pingouin.pairwise_tukey.html#pingouin.pairwise_tukey @@ -210,14 +224,14 @@ def tukey_test(self, protein_id, group, df=None): return tukey_df - #@lru_cache(maxsize=20) + # @lru_cache(maxsize=20) @ignore_warning(RuntimeWarning) - def anova(self, column, protein_ids="all", tukey=True): + def anova(self, column: str, protein_ids: str = "all", tukey: bool = True): """One-way Analysis of Variance (ANOVA) Args: column (str): A metadata column used to calculate ANOVA - ids (str or list, optional): ProteinIDs to calculate ANOVA for - dependend variable either ProteinID as string, several ProteinIDs as list or "all" to calculate ANOVA for all ProteinIDs. Defaults to "all". + protein_ids (str or list, optional): ProteinIDs to calculate ANOVA for - dependend variable either ProteinID as string, several ProteinIDs as list or "all" to calculate ANOVA for all ProteinIDs. Defaults to "all". tukey (bool, optional): Whether to calculate a Tukey-HSD post-hoc test. Defaults to True. Returns: @@ -266,7 +280,7 @@ def anova(self, column, protein_ids="all", tukey=True): final_df = anova_df return final_df - def _create_tukey_df(self, anova_df, protein_ids_list, group): + def _create_tukey_df(self, anova_df, protein_ids_list, group) -> pd.DataFrame: #  combine tukey results with anova results df = ( self.mat[protein_ids_list] @@ -295,7 +309,9 @@ def _create_tukey_df(self, anova_df, protein_ids_list, group): return final_df @lru_cache(maxsize=20) - def ancova(self, protein_id, covar, between): + def ancova( + self, protein_id: Union[str, list], covar: Union[str, list], between: str + ) -> pd.DataFrame: """Analysis of covariance (ANCOVA) with on or more covariate(s). Wrapper around = https://pingouin-stats.org/generated/pingouin.ancova.html @@ -320,34 +336,34 @@ def ancova(self, protein_id, covar, between): df = self.metadata.merge(df, how="inner", on=[self.sample]) ancova_df = pingouin.ancova(df, dv=protein_id, covar=covar, between=between) return ancova_df - + def multi_covariat_analysis( - self, - covariates:list, - n_permutations=3, - fdr=0.05, - s0=0.05, - subset:dict - ): - """Multicovarait Analysis + self, + covariates: list, + n_permutations: int = 3, + fdr: float = 0.05, + s0: float = 0.05, + subset: dict = None, + ) -> pd.DataFrame: + """_summary_ Args: - covariates (list): List of covariates, column names in metadata - subset (dict): _description_ - n_permutations (int, optional): _description_. Defaults to 3. - fdr (float, optional): _description_. Defaults to 0.05. + covariates (list): list of covariates, column names in metadata + n_permutations (int, optional): number of permutations. Defaults to 3. + fdr (float, optional): False Discovery Rate. Defaults to 0.05. s0 (float, optional): _description_. Defaults to 0.05. + subset (dict, optional): _description_. Defaults to None. Returns: - _type_: _description_ + pd.DataFrame: _description_ """ + res = MultiCovaAnalysis( dataset=self, covariates=covariates, n_permutations=n_permutations, fdr=fdr, s0=s0, - subset=subset + subset=subset, ).calculate() return res - From df032f13210f2e73be4dcac02ea12f55b9fe409c Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Mon, 13 Mar 2023 16:46:04 +0100 Subject: [PATCH 03/17] style with black --- Untitled.ipynb | 45796 ++++++++++++++++ alphastats/DataSet.py | 11 +- alphastats/cli.py | 6 +- alphastats/gui/AlphaPeptStats.py | 7 +- alphastats/gui/__init__.py | 2 +- alphastats/gui/pages/02_Import Data.py | 55 +- alphastats/gui/pages/03_Data Overview.py | 14 +- alphastats/gui/pages/03_Preprocessing.py | 28 +- alphastats/gui/pages/04_Analysis.py | 37 +- alphastats/gui/pages/06_Results.py | 2 +- alphastats/gui/utils/analysis_helper.py | 64 +- alphastats/gui/utils/ui_helper.py | 1 - alphastats/loader/BaseLoader.py | 2 +- alphastats/loader/SpectronautLoader.py | 69 +- alphastats/multicova/multicova.py | 551 +- alphastats/plots/ClusterMap.py | 35 +- alphastats/plots/DimensionalityReduction.py | 6 +- alphastats/plots/IntensityPlot.py | 50 +- alphastats/plots/PlotUtils.py | 5 +- alphastats/plots/VolcanoPlot.py | 180 +- alphastats/statistics/MultiCovaAnalysis.py | 73 +- alphastats/utils.py | 5 +- release/pyinstaller/alphastats_pyinstaller.py | 6 +- setup.py | 14 +- tests/test_DataSet.py | 151 +- tests/test_DataSet_Pathway.py | 8 +- tests/test_loaders.py | 35 +- 27 files changed, 46659 insertions(+), 554 deletions(-) create mode 100644 Untitled.ipynb diff --git a/Untitled.ipynb b/Untitled.ipynb new file mode 100644 index 00000000..a5c1fcfc --- /dev/null +++ b/Untitled.ipynb @@ -0,0 +1,45796 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 6, + "id": "05f4ea55", + "metadata": {}, + "outputs": [], + "source": [ + "import alphastats" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "f35011c1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "DataSet has been created.\n", + "Attributes of the DataSet can be accessed using: \n", + "DataSet.rawinput:\t Raw Protein data.\n", + "DataSet.mat:\tProcessed data matrix with ProteinIDs/ProteinGroups as columns and samples as rows. All computations are performed on this matrix.\n", + "DataSet.metadata:\tMetadata for the samples in the matrix. Metadata will be matched with DataSet.mat when needed (for instance Volcano Plot).\n" + ] + } + ], + "source": [ + "loader = alphastats.MaxQuantLoader(\n", + " file = \"testfiles/maxquant/proteinGroups.txt\", \n", + " intensity_column=\"LFQ intensity [sample]\",\n", + " # for indexing we are going to use the gene name columm\n", + " # it is adivsed to use the ProteinIDs for indexing as these are unique\n", + " index_column=\"Gene names\",\n", + " gene_names_column=None\n", + ")\n", + "dataset = alphastats.DataSet(\n", + " loader = loader, \n", + " metadata_path=\"testfiles/maxquant/metadata.xlsx\", \n", + " sample_column=\"sample\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "dd414acd", + "metadata": {}, + "outputs": [], + "source": [ + "dataset.preprocess(imputation=\"knn\", normalization=\"zscore\", subset=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "d307e964", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Calculating t-test and permuation based FDR (SAM)... \n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "26ace183d0e44909a8d4c6f163868c37", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Pandas Apply: 0%| | 0/899 [00:00\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Gene namesfctvalpvaltval_s0pval_s0qvalFDRlog2fc-log10(p-value)color
2VCL;HEL114-0.717938-1.7055750.107421-1.5244910.1469070.0sig-0.7179380.968910down
4C90.3467362.0836780.0535831.6022500.1286560.0sig0.3467361.270973up
7APOC10.4194402.6831960.0163242.0329480.0589950.0sig0.4194401.787176up
13APOL1-0.107541-0.5880010.564739-0.4617630.6504680.0sig-0.1075410.248152down
29CLEC3B-0.069258-0.3864700.704240-0.3021650.7664190.0sig-0.0692580.152280down
....................................
850PGLYRP20.0679200.7286160.4767660.4742420.6417350.0sig0.0679200.321694up
876C1RL0.2635651.5303200.1454671.1860080.2529330.0sig0.2635650.837234up
881PCYOX10.2795811.0351020.3160140.8734180.3953550.0sig0.2795810.500294up
897APOA2-0.075631-0.6398760.531309-0.4496580.6589890.0sig-0.0756310.274652down
898HEL-214-0.160419-2.1465150.047510-1.2860820.2167150.0sig-0.1604191.323217down
\n", + "

180 rows × 11 columns

\n", + "" + ], + "text/plain": [ + " Gene names fc tval pval tval_s0 pval_s0 qval FDR \\\n", + "2 VCL;HEL114 -0.717938 -1.705575 0.107421 -1.524491 0.146907 0.0 sig \n", + "4 C9 0.346736 2.083678 0.053583 1.602250 0.128656 0.0 sig \n", + "7 APOC1 0.419440 2.683196 0.016324 2.032948 0.058995 0.0 sig \n", + "13 APOL1 -0.107541 -0.588001 0.564739 -0.461763 0.650468 0.0 sig \n", + "29 CLEC3B -0.069258 -0.386470 0.704240 -0.302165 0.766419 0.0 sig \n", + ".. ... ... ... ... ... ... ... ... \n", + "850 PGLYRP2 0.067920 0.728616 0.476766 0.474242 0.641735 0.0 sig \n", + "876 C1RL 0.263565 1.530320 0.145467 1.186008 0.252933 0.0 sig \n", + "881 PCYOX1 0.279581 1.035102 0.316014 0.873418 0.395355 0.0 sig \n", + "897 APOA2 -0.075631 -0.639876 0.531309 -0.449658 0.658989 0.0 sig \n", + "898 HEL-214 -0.160419 -2.146515 0.047510 -1.286082 0.216715 0.0 sig \n", + "\n", + " log2fc -log10(p-value) color \n", + "2 -0.717938 0.968910 down \n", + "4 0.346736 1.270973 up \n", + "7 0.419440 1.787176 up \n", + "13 -0.107541 0.248152 down \n", + "29 -0.069258 0.152280 down \n", + ".. ... ... ... \n", + "850 0.067920 0.321694 up \n", + "876 0.263565 0.837234 up \n", + "881 0.279581 0.500294 up \n", + "897 -0.075631 0.274652 down \n", + "898 -0.160419 1.323217 down \n", + "\n", + "[180 rows x 11 columns]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "plot.plotting_data" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "bc721fb1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
1_31_C61_32_C71_33_C81_34_C91_35_C101_36_C111_37_C121_38_D11_39_D21_40_D3...1_77_G41_78_G5Gene namesfctvalpvaltval_s0pval_s0qvalFDR 1%
0-inf-inf-inf-inf-inf-inf-inf21.147868-inf-inf...-inf-infSERPINE1NaNNaNNaNNaNNaNNaNnon_sig
1-inf-inf-inf-inf-inf23.523368-inf-inf-inf-inf...-inf-infMYH11NaNNaNNaNNaNNaNNaNnon_sig
227.12198628.56550828.15330127.10289625.79555728.07663527.73866627.51690728.41163227.460374...26.78394225.764788VCL;HEL114-0.717938-1.7055750.107421-1.5244910.1469070.0sig
3-inf-inf-inf22.322951-inf-inf-inf-inf-inf-inf...-inf-infPSAPNaNNaNNaNNaNNaNNaNnon_sig
431.90551731.30720532.45024632.39973432.04433432.25898132.07469731.69000032.19759432.307097...31.53059832.132191C90.3467362.0836780.0535831.6022500.1286560.0sig
..................................................................
89423.013845-inf-inf-inf-inf23.038034-inf-inf-inf-inf...-inf-infPLXND1NaNNaNNaNNaNNaNNaNnon_sig
89527.272576-inf26.15665124.90251426.796621-inf-inf-inf27.851326-inf...26.896891-infHYOU1NaNNaNNaNNaNNaNNaNnon_sig
896-inf-inf-inf-inf-inf-inf-inf-inf-inf-inf...-inf-infAPOBNaNNaNNaNNaNNaNNaNnon_sig
89733.92193834.21798234.07996634.16862934.46221933.92556834.07821734.10094634.24296234.303481...34.20965533.585421APOA2-0.075631-0.6398760.531309-0.4496580.6589890.0sig
89836.54466736.20490936.12953436.28869136.75806736.68342636.57274536.69072936.72364736.229810...36.47078836.186044HEL-214-0.160419-2.1465150.047510-1.2860820.2167150.0sig
\n", + "

899 rows × 56 columns

\n", + "
" + ], + "text/plain": [ + " 1_31_C6 1_32_C7 1_33_C8 1_34_C9 1_35_C10 1_36_C11 \\\n", + "0 -inf -inf -inf -inf -inf -inf \n", + "1 -inf -inf -inf -inf -inf 23.523368 \n", + "2 27.121986 28.565508 28.153301 27.102896 25.795557 28.076635 \n", + "3 -inf -inf -inf 22.322951 -inf -inf \n", + "4 31.905517 31.307205 32.450246 32.399734 32.044334 32.258981 \n", + ".. ... ... ... ... ... ... \n", + "894 23.013845 -inf -inf -inf -inf 23.038034 \n", + "895 27.272576 -inf 26.156651 24.902514 26.796621 -inf \n", + "896 -inf -inf -inf -inf -inf -inf \n", + "897 33.921938 34.217982 34.079966 34.168629 34.462219 33.925568 \n", + "898 36.544667 36.204909 36.129534 36.288691 36.758067 36.683426 \n", + "\n", + " 1_37_C12 1_38_D1 1_39_D2 1_40_D3 ... 1_77_G4 1_78_G5 \\\n", + "0 -inf 21.147868 -inf -inf ... -inf -inf \n", + "1 -inf -inf -inf -inf ... -inf -inf \n", + "2 27.738666 27.516907 28.411632 27.460374 ... 26.783942 25.764788 \n", + "3 -inf -inf -inf -inf ... -inf -inf \n", + "4 32.074697 31.690000 32.197594 32.307097 ... 31.530598 32.132191 \n", + ".. ... ... ... ... ... ... ... \n", + "894 -inf -inf -inf -inf ... -inf -inf \n", + "895 -inf -inf 27.851326 -inf ... 26.896891 -inf \n", + "896 -inf -inf -inf -inf ... -inf -inf \n", + "897 34.078217 34.100946 34.242962 34.303481 ... 34.209655 33.585421 \n", + "898 36.572745 36.690729 36.723647 36.229810 ... 36.470788 36.186044 \n", + "\n", + " Gene names fc tval pval tval_s0 pval_s0 qval \\\n", + "0 SERPINE1 NaN NaN NaN NaN NaN NaN \n", + "1 MYH11 NaN NaN NaN NaN NaN NaN \n", + "2 VCL;HEL114 -0.717938 -1.705575 0.107421 -1.524491 0.146907 0.0 \n", + "3 PSAP NaN NaN NaN NaN NaN NaN \n", + "4 C9 0.346736 2.083678 0.053583 1.602250 0.128656 0.0 \n", + ".. ... ... ... ... ... ... ... \n", + "894 PLXND1 NaN NaN NaN NaN NaN NaN \n", + "895 HYOU1 NaN NaN NaN NaN NaN NaN \n", + "896 APOB NaN NaN NaN NaN NaN NaN \n", + "897 APOA2 -0.075631 -0.639876 0.531309 -0.449658 0.658989 0.0 \n", + "898 HEL-214 -0.160419 -2.146515 0.047510 -1.286082 0.216715 0.0 \n", + "\n", + " FDR 1% \n", + "0 non_sig \n", + "1 non_sig \n", + "2 sig \n", + "3 non_sig \n", + "4 sig \n", + ".. ... \n", + "894 non_sig \n", + "895 non_sig \n", + "896 non_sig \n", + "897 sig \n", + "898 sig \n", + "\n", + "[899 rows x 56 columns]" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "res_ttest" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "af7858a2", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "customdata": [ + [ + "SERPINE1" + ], + [ + "MYH11" + ], + [ + "VCL;HEL114" + ], + [ + "PSAP" + ], + [ + "C9" + ], + [ + "CAPZA1" + ], + [ + "PLD3" + ], + [ + "APOC1" + ], + [ + "NELL2" + ], + [ + "CNTN1" + ], + [ + "ALDOB" + ], + [ + "GGT1;hCG_2010666;GGT2;GGT3P" + ], + [ + "MB" + ], + [ + "APOL1" + ], + [ + "UPB1;DKFZp779O1248" + ], + [ + "YWHAH" + ], + [ + "NPTXR" + ], + [ + "NAGA" + ], + [ + "IGFBP4" + ], + [ + "JUP" + ], + [ + "KRT23" + ], + [ + "PSME3;HEL-S-283" + ], + [ + "VPS13A" + ], + [ + "TJP2" + ], + [ + "RPL17;LOC402695;hCG_24487;RPL17-C18orf32;LOC202789" + ], + [ + "LMAN1" + ], + [ + "SERPINB5" + ], + [ + "CNTN4" + ], + [ + "RPL15;LOC136321" + ], + [ + "CLEC3B" + ], + [ + "DAG1" + ], + [ + "LAMB2" + ], + [ + "CTSB" + ], + [ + "DLAT" + ], + [ + "APOA1" + ], + [ + "TMEM25" + ], + [ + "MCAM" + ], + [ + "NRP2;DKFZp686J1169" + ], + [ + "EEF1B2;LOC392793" + ], + [ + "HSPD1" + ], + [ + "BZW1;hCG_2022736" + ], + [ + "IGFBP5" + ], + [ + "ENO1" + ], + [ + "PLOD1" + ], + [ + "LZIC" + ], + [ + "KLK6" + ], + [ + "CYB5R3" + ], + [ + "DAK;TKFC;DKFZp586B1621" + ], + [ + "PRCP" + ], + [ + "ANXA2;HEL-S-270;ANXA2P2" + ], + [ + "RAB11A;RAB11B" + ], + [ + "PKM2;PKM" + ], + [ + "CLN5" + ], + [ + "LGALS3;hCG_22119" + ], + [ + "ACTN1" + ], + [ + "FBLN5" + ], + [ + "SERPINA10" + ], + [ + "SERPINA1" + ], + [ + "SERPINA4" + ], + [ + "WARS" + ], + [ + "SERPINA5" + ], + [ + "SERPINA3" + ], + [ + "MMP2" + ], + [ + "DPEP2" + ], + [ + "MET" + ], + [ + "BPGM" + ], + [ + "ICAM3;hCG_2033729" + ], + [ + "FGFR4" + ], + [ + "ALAD" + ], + [ + "ENG" + ], + [ + "TNC;TNC variant protein" + ], + [ + "SET" + ], + [ + "ADAMTSL2" + ], + [ + "LCN1" + ], + [ + "COL5A1" + ], + [ + "PTGDS" + ], + [ + "P4HB" + ], + [ + "SELL" + ], + [ + "PKP1" + ], + [ + "CHI3L1" + ], + [ + "LAMC1" + ], + [ + "CPQ;PGCP" + ], + [ + "COLEC10" + ], + [ + "C1QC" + ], + [ + "HSPG2" + ], + [ + "C1QB" + ], + [ + "ALPL" + ], + [ + "C1QA" + ], + [ + "HEXB" + ], + [ + "VCAN;CSPG2" + ], + [ + "ARHGDIB" + ], + [ + "CORO1C" + ], + [ + "CDH2" + ], + [ + "GALNT1" + ], + [ + "ANPEP" + ], + [ + "DDR1" + ], + [ + "PLA2G7" + ], + [ + "HSP90AB1" + ], + [ + "IGFBP7" + ], + [ + "SPARCL1" + ], + [ + "SPP1;opn" + ], + [ + "ADH4;HEL-S-4" + ], + [ + "ASL" + ], + [ + "LCP1;HEL-S-37" + ], + [ + "LAMP1" + ], + [ + "BCAM;LU" + ], + [ + "V3-4;IGLV8-61" + ], + [ + "V5-4;IGLV4-60" + ], + [ + "V2-6;IGLV3-9" + ], + [ + "IGKV2D-28" + ], + [ + "IGHV4-4" + ], + [ + "IGKV2-24;IGKV2D-24" + ], + [ + "PTPRC" + ], + [ + "NUCB2;HEL-S-109;Nucb2" + ], + [ + "UCHL3" + ], + [ + "NCAM1" + ], + [ + "PTPRJ" + ], + [ + "ROBO1" + ], + [ + "MYCBP" + ], + [ + "OSCAR" + ], + [ + "PRSS1;PRSS3P2" + ], + [ + "TNXB" + ], + [ + "LAMA2" + ], + [ + "ST3GAL6" + ], + [ + "FCGBP" + ], + [ + "CDH1" + ], + [ + "IGHM" + ], + [ + "SEZ6L2;PSK-1" + ], + [ + "UGP2" + ], + [ + "EIF3H;EIF3S3" + ], + [ + "FCGR3B;Fc-gamma receptor IIIB" + ], + [ + "CADM1" + ], + [ + "COL15A1" + ], + [ + "CHL1" + ], + [ + "COL6A1" + ], + [ + "NOMO2;NOMO1;NOMO3" + ], + [ + "GPX3" + ], + [ + "NEB" + ], + [ + "PSME2" + ], + [ + "AGRN" + ], + [ + "C1S" + ], + [ + "CNN2" + ], + [ + "PDIA4;ERP70" + ], + [ + "C21orf33" + ], + [ + "SAA2-SAA4;SAA4" + ], + [ + "CACHD1" + ], + [ + "APP" + ], + [ + "F5" + ], + [ + "PDE4DIP;CDK5RAP2;DKFZp686M1993" + ], + [ + "SVEP1" + ], + [ + "PLS3" + ], + [ + "RGMA" + ], + [ + "TTN" + ], + [ + "IL6ST" + ], + [ + "CNTFR" + ], + [ + "HPD" + ], + [ + "VH6DJ;IGHV6-1" + ], + [ + "IGHV3-74" + ], + [ + "V5-2;IGLV9-49" + ], + [ + "IGHV3-72" + ], + [ + "SRSF7;SRSF3;SFRS3" + ], + [ + "LYZ" + ], + [ + "IGKV1D-13" + ], + [ + "CRTAC1" + ], + [ + "COL11A2" + ], + [ + "SELPLG" + ], + [ + "CES3" + ], + [ + "GP1BA" + ], + [ + "IGKV6-21" + ], + [ + "IGHV1-3;IGHM" + ], + [ + "IGHV3-38" + ], + [ + "IGHV5-51" + ], + [ + "IGKV1-8;IGKV1-9" + ], + [ + "FAP" + ], + [ + "NTRK3" + ], + [ + "LRRFIP1" + ], + [ + "HLA-DRA;HLA-DRA1;HLA-DQA1/DRA" + ], + [ + "LILRA2" + ], + [ + "LILRA6;LILRB3" + ], + [ + "CDHR5;MUPCDH" + ], + [ + "LILRB5;FLJ00275" + ], + [ + "LILRA3" + ], + [ + "PRB4" + ], + [ + "V4-2;IGLV5-45" + ], + [ + "TPM1" + ], + [ + "CST3" + ], + [ + "PSMA7" + ], + [ + "PSME1" + ], + [ + "APOE" + ], + [ + "CETP" + ], + [ + "FGFR1" + ], + [ + "EFEMP1" + ], + [ + "MYOC" + ], + [ + "PCK2" + ], + [ + "NPM1" + ], + [ + "DKFZp686J1372;TPM3" + ], + [ + "HEL-S-82p;TPM3" + ], + [ + "CFP" + ], + [ + "PROS1" + ], + [ + "TGFBI" + ], + [ + "PRG4" + ], + [ + "KIT" + ], + [ + "MYH9" + ], + [ + "ART4;DO" + ], + [ + "IGHV1-24" + ], + [ + "TNXB" + ], + [ + "NAGLU;ufHSD2" + ], + [ + "DPEP1" + ], + [ + "ECM1" + ], + [ + "ESD" + ], + [ + "FGG;DKFZp779N0926" + ], + [ + "GSTA2;GSTA1;GSTalpha locus;GSTA3;GSTA5" + ], + [ + "HPRT1" + ], + [ + "KCTD12" + ], + [ + "PEPD" + ], + [ + "SOD3" + ], + [ + "STMN1" + ], + [ + "AZGP1" + ], + [ + "LCAT" + ], + [ + "LTA4H" + ], + [ + "PSMA3" + ], + [ + "PSMB4" + ], + [ + "TALDO1" + ], + [ + "CALD1" + ], + [ + "ST13;ST13P5;ST13P4" + ], + [ + "SERPINF1" + ], + [ + "ISLR" + ], + [ + "LTF;HEL110" + ], + [ + "ACHE" + ], + [ + "SEPP1" + ], + [ + "V2-13;VL4" + ], + [ + "CTSD;HEL-S-130P" + ], + [ + "FAS;CD95;TNFRSF6" + ], + [ + "KRT83;KRT86;KRT81;KRT87P" + ], + [ + "IGLC7" + ], + [ + "HBD" + ], + [ + "V3" + ], + [ + "F5-20" + ], + [ + "KRT13" + ], + [ + "MSTN;GDF8" + ], + [ + "SSC5D" + ], + [ + "RPS6" + ], + [ + "A30" + ], + [ + "VK3" + ], + [ + "IGH@" + ], + [ + "IGKV A18" + ], + [ + "ITIH2" + ], + [ + "CSF1R" + ], + [ + "GNPTG;RJD9" + ], + [ + "APOC3" + ], + [ + "F7" + ], + [ + "ATP6V1F" + ], + [ + "CPA4" + ], + [ + "PCOLCE" + ], + [ + "RPS4X;RPS4Y1;RPS4Y2" + ], + [ + "ANTXR2" + ], + [ + "PDCD1LG2;PDL2" + ], + [ + "GGT7" + ], + [ + "CP" + ], + [ + "APOL1" + ], + [ + "APOC4" + ], + [ + "BST1" + ], + [ + "BGN" + ], + [ + "TTR;HEL111" + ], + [ + "IGFBP3" + ], + [ + "B2M" + ], + [ + "CFD;DF" + ], + [ + "PCDH9" + ], + [ + "IGHG1" + ], + [ + "ANGPTL3" + ], + [ + "GPR116" + ], + [ + "PCDH1" + ], + [ + "OLFM1" + ], + [ + "L1CAM" + ], + [ + "CNDP1" + ], + [ + "LEPR" + ], + [ + "PSMC4" + ], + [ + "C1S" + ], + [ + "DSC2;DKFZp686P18250;DKFZp686I11137" + ], + [ + "C7" + ], + [ + "EPHA1" + ], + [ + "EGFR" + ], + [ + "GSPT1;GSPT2" + ], + [ + "GGH" + ], + [ + "COMP" + ], + [ + "ACTC1;ACTA1" + ], + [ + "SECTM1" + ], + [ + "PHB;HEL-S-54e" + ], + [ + "UBE2I" + ], + [ + "C1QBP" + ], + [ + "ADIPOQ" + ], + [ + "UBC;UBB;RPS27A;UBA52;HEL112;DKFZp434K0435;UbC" + ], + [ + "STIP1;HEL-S-94n" + ], + [ + "MAN2B1" + ], + [ + "MANBA" + ], + [ + "IL1RAP" + ], + [ + "REG1A;REG1B" + ], + [ + "NUCB1" + ], + [ + "LMAN2" + ], + [ + "G6PD" + ], + [ + "CDSN;S" + ], + [ + "ELTD1" + ], + [ + "IGFALS" + ], + [ + "ENPEP" + ], + [ + "SEZ6L" + ], + [ + "PROZ" + ], + [ + "AGT" + ], + [ + "FBLN1" + ], + [ + "PSMD10" + ], + [ + "CFHR1" + ], + [ + "CD58" + ], + [ + "CASP14" + ], + [ + "HIST1H4A;HIST1H4H" + ], + [ + "DKFZp686H17246" + ], + [ + "IDH1;HEL-S-26;HEL-216" + ], + [ + "APLP1" + ], + [ + "LYVE1;XLKD1" + ], + [ + "GUSB" + ], + [ + "ERAP2" + ], + [ + "CDH17" + ], + [ + "MINPP1" + ], + [ + "OMD" + ], + [ + "BPIFB1" + ], + [ + "CD14" + ], + [ + "PZP" + ], + [ + "GSTO1;HEL-S-21" + ], + [ + "CFHR5" + ], + [ + "KIAA0319L" + ], + [ + "CTBS" + ], + [ + "INHBC" + ], + [ + "PCDH12" + ], + [ + "BHMT;HEL-S-61p" + ], + [ + "LSAMP" + ], + [ + "SPARC" + ], + [ + "CALM1;CALM3;CALM2" + ], + [ + "MERTK" + ], + [ + "ITIH4;DKFZp686G21125" + ], + [ + "LCN2;NGAL" + ], + [ + "SNX2;SNX1" + ], + [ + "YWHAG" + ], + [ + "GOLM1;GOLPH2" + ], + [ + "TUBA1B;TUBA1A" + ], + [ + "CALU" + ], + [ + "PDIA3;HEL-S-269" + ], + [ + "PVR" + ], + [ + "FSCN1" + ], + [ + "SIRPB2" + ], + [ + "UMOD" + ], + [ + "PLTP" + ], + [ + "CHL1" + ], + [ + "TNN" + ], + [ + "C1QTNF3;C1QTNF3-AMACR" + ], + [ + "HADHA" + ], + [ + "PGM1" + ], + [ + "HSPA4;HEL-S-5a" + ], + [ + "C16orf46" + ], + [ + "SUSD5" + ], + [ + "GANAB;HEL-S-164nA" + ], + [ + "GART" + ], + [ + "PRKCSH" + ], + [ + "CRLF3" + ], + [ + "ECM2" + ], + [ + "GALNT6" + ], + [ + "GDI2" + ], + [ + "KNG1" + ], + [ + "C1R" + ], + [ + "PROC" + ], + [ + "INPP5D" + ], + [ + "NCSTN" + ], + [ + "KRT4" + ], + [ + "CD93" + ], + [ + "HAGH" + ], + [ + "SPINT1" + ], + [ + "PSMD11" + ], + [ + "TIE1;TIE" + ], + [ + "ITGA1" + ], + [ + "IVL" + ], + [ + "HEXA" + ], + [ + "ATRN" + ], + [ + "GAS6" + ], + [ + "ITGB2" + ], + [ + "PTPRM" + ], + [ + "KNG1" + ], + [ + "C4BPA" + ], + [ + "GRN" + ], + [ + "CFB" + ], + [ + "LAMP2" + ], + [ + "SLC3A2" + ], + [ + "CTSA;PPGB" + ], + [ + "DPP3;DKFZp686O1117" + ], + [ + "PLXDC2" + ], + [ + "CLSTN1" + ], + [ + "CECR1" + ], + [ + "EIF2S2" + ], + [ + "SSB" + ], + [ + "TCN2" + ], + [ + "ESRRG;ESRRB;NR3B3;ERRgamma" + ], + [ + "HBG2;HBG1" + ], + [ + "CCT7" + ], + [ + "TUBA1C" + ], + [ + "CCT4" + ], + [ + "C8B" + ], + [ + "MAN2B2" + ], + [ + "CAST" + ], + [ + "POMGNT1" + ], + [ + "DCBLD2" + ], + [ + "AHSG" + ], + [ + "CDH13" + ], + [ + "ITIH4" + ], + [ + "RTN4RL2" + ], + [ + "AMY1A;AMY1B" + ], + [ + "PTMA;PTMAP7" + ], + [ + "MRC1;MRC1L1" + ], + [ + "APOB" + ], + [ + "IGFBP1" + ], + [ + "TGFBI" + ], + [ + "C1S" + ], + [ + "IGJ;JCHAIN" + ], + [ + "APOD" + ], + [ + "CD163" + ], + [ + "SEMA3F" + ], + [ + "NRCAM" + ], + [ + "DMKN" + ], + [ + "KRT75" + ], + [ + "KRT14" + ], + [ + "ALB" + ], + [ + "KRT16" + ], + [ + "KRT10" + ], + [ + "KRT5" + ], + [ + "KRT2" + ], + [ + "FLG2" + ], + [ + "KRT80" + ], + [ + "KRT78" + ], + [ + "KRT25" + ], + [ + "HRNR" + ], + [ + "KRTHB2;KRT82" + ], + [ + "YWHAZ" + ], + [ + "HBA1;HBA2" + ], + [ + "BCHE" + ], + [ + "FGG" + ], + [ + "SH3BGRL3;HEL-S-297" + ], + [ + "CAP1" + ], + [ + "DKFZp686P17171;SERBP1" + ], + [ + "EXT2" + ], + [ + "GLIPR2;C9orf19" + ], + [ + "COL18A1" + ], + [ + "ICAM2" + ], + [ + "ABI3BP" + ], + [ + "HGFAC" + ], + [ + "LECT2" + ], + [ + "GC" + ], + [ + "CDH6" + ], + [ + "COL12A1" + ], + [ + "CCDC88A;KIAA1212" + ], + [ + "SFTPB" + ], + [ + "PTPRS" + ], + [ + "PEBP1;HEL-S-34" + ], + [ + "APOH" + ], + [ + "HBB" + ], + [ + "COL6A3;DKFZp686K04147" + ], + [ + "SHH" + ], + [ + "VTN" + ], + [ + "PRAP1" + ], + [ + "SLC4A1" + ], + [ + "TBCA" + ], + [ + "FABP5" + ], + [ + "SNCA;NACP" + ], + [ + "EZR;HEL-S-105;EZR-ROS1" + ], + [ + "CFI" + ], + [ + "ENPP2" + ], + [ + "LTBP1" + ], + [ + "PIEZO2" + ], + [ + "SERPINA1" + ], + [ + "SERPING1" + ], + [ + "KLKB1" + ], + [ + "FLT4;VEGFR3" + ], + [ + "CR1" + ], + [ + "NRP1;DKFZp781F1414;DKFZp686A03134" + ], + [ + "CFL1;HEL-S-15" + ], + [ + "F9;F9 p22;factor IX F9" + ], + [ + "HLA-A;HLA;MHC class I HLA-A;HLA-A*02;HLA-A2;HLA-B;HLA-A*0225" + ], + [ + "WFDC3" + ], + [ + "PHB2" + ], + [ + "GPR133;ADGRD1" + ], + [ + "PTPRB;DKFZp686E13109;DKFZp686E2262;DKFZp686H15164" + ], + [ + "CDH19" + ], + [ + "GOLIM4" + ], + [ + "TGOLN2" + ], + [ + "SERPINA3" + ], + [ + "LAMB1" + ], + [ + "MST1" + ], + [ + "KLKB1" + ], + [ + "CDON" + ], + [ + "B2M" + ], + [ + "MSLN" + ], + [ + "KRT1" + ], + [ + "CD86" + ], + [ + "SHBG" + ], + [ + "CAMP" + ], + [ + "MYL6" + ], + [ + "SEMA4B;DKFZp686A04130" + ], + [ + "RELN" + ], + [ + "GSDMA" + ], + [ + "TPM4" + ], + [ + "TPM4" + ], + [ + "CILP2" + ], + [ + "APOC4-APOC2;APOC2" + ], + [ + "HSP90AA1;EL52" + ], + [ + "VWF" + ], + [ + "C3" + ], + [ + "ECH1" + ], + [ + "PDLIM1;HEL-S-112" + ], + [ + "MASP2" + ], + [ + "SIRPB1" + ], + [ + "PGRMC1" + ], + [ + "CLIC1" + ], + [ + "QSOX1;BPGF-1" + ], + [ + "FCN1;DKFZp781B1032" + ], + [ + "PLXNB2" + ], + [ + "PLXNB1" + ], + [ + "TREH" + ], + [ + "RGS10" + ], + [ + "CD5L" + ], + [ + "XPNPEP2" + ], + [ + "FIGF" + ], + [ + "SEMA7A" + ], + [ + "CILP" + ], + [ + "PDCD6" + ], + [ + "FCN3;UNQ172" + ], + [ + "PAPLN" + ], + [ + "H6PD" + ], + [ + "VNN1" + ], + [ + "LDHA;HEL-S-133P" + ], + [ + "ALDH1A1;HEL-S-53e;HEL-9" + ], + [ + "GSR;HEL-75" + ], + [ + "F8" + ], + [ + "F13A1" + ], + [ + "PNP;HEL-S-156an" + ], + [ + "PGK1;HEL-S-68p" + ], + [ + "F2" + ], + [ + "HP" + ], + [ + "HPR" + ], + [ + "F10" + ], + [ + "PLG" + ], + [ + "F12" + ], + [ + "CA1;HEL-S-11" + ], + [ + "CA2;HEL-76" + ], + [ + "A2M" + ], + [ + "C3;HEL-S-62p" + ], + [ + "C5" + ], + [ + "CSTA" + ], + [ + "PIGR" + ], + [ + "IGHG4" + ], + [ + "COL3A1" + ], + [ + "LMNA" + ], + [ + "FGA" + ], + [ + "FGB;HEL-S-78p" + ], + [ + "FGG" + ], + [ + "CRP" + ], + [ + "APCS;HEL-S-92n" + ], + [ + "LRG1" + ], + [ + "FN1" + ], + [ + "RBP4" + ], + [ + "AMBP" + ], + [ + "ORM1;HEL-S-153w" + ], + [ + "GC;HEL-S-51" + ], + [ + "PPBP" + ], + [ + "TFRC" + ], + [ + "TF" + ], + [ + "HPX" + ], + [ + "FTL;FTL variant" + ], + [ + "ANG;RAA1" + ], + [ + "F11" + ], + [ + "CAT" + ], + [ + "FUCA1" + ], + [ + "ALDOA;HEL-S-87p" + ], + [ + "CSTB" + ], + [ + "ANXA1" + ], + [ + "HRG" + ], + [ + "HEL-S-163pA;A1BG" + ], + [ + "VWF" + ], + [ + "GAPDH;HEL-S-162eP" + ], + [ + "HSPB1;HEL-S-102" + ], + [ + "CHGB" + ], + [ + "ARG1" + ], + [ + "S100A8" + ], + [ + "F13B" + ], + [ + "ICAM1" + ], + [ + "SERPINA7" + ], + [ + "SERPIND1" + ], + [ + "ITGB1" + ], + [ + "GSN" + ], + [ + "C2" + ], + [ + "S100A9" + ], + [ + "S100A6" + ], + [ + "APOA4" + ], + [ + "CKM" + ], + [ + "LDHB" + ], + [ + "ASGR2;HBXBP" + ], + [ + "C8A" + ], + [ + "C8G" + ], + [ + "TUBB;XTP3TPATP1" + ], + [ + "CA3;HEL-S-167mP" + ], + [ + "PFN1" + ], + [ + "EPRS" + ], + [ + "THBS1" + ], + [ + "RNASE1;RAC1" + ], + [ + "SERPINA6" + ], + [ + "LPA" + ], + [ + "CFH" + ], + [ + "VIM;HEL113" + ], + [ + "SERPINF2" + ], + [ + "ANXA5;HEL-S-7" + ], + [ + "DBH" + ], + [ + "LGALS1" + ], + [ + "PDGFRB" + ], + [ + "C4A" + ], + [ + "C4B" + ], + [ + "SAA1" + ], + [ + "SAA2" + ], + [ + "IGHD" + ], + [ + "PTPRF;LAR" + ], + [ + "CHGA" + ], + [ + "CLU" + ], + [ + "HSPA5;HEL-S-89n" + ], + [ + "HSPA8;HEL-S-72p" + ], + [ + "MBL2" + ], + [ + "IGF2R" + ], + [ + "COL6A2" + ], + [ + "PIP" + ], + [ + "FCGR2A;FCGR2C;FCGR2B" + ], + [ + "ACE" + ], + [ + "MYH7;MYH6" + ], + [ + "NCAM1" + ], + [ + "EEF2" + ], + [ + "C6" + ], + [ + "CEACAM1" + ], + [ + "PRG2" + ], + [ + "CD99" + ], + [ + "NID1" + ], + [ + "PKM;HEL-S-30;PKM2" + ], + [ + "HSP90B1;TRA1;HEL-S-125m" + ], + [ + "IDE" + ], + [ + "CPA1" + ], + [ + "CPN1" + ], + [ + "ST6GAL1" + ], + [ + "DSP;DSP variant protein" + ], + [ + "CD44" + ], + [ + "PNLIP" + ], + [ + "PECAM1" + ], + [ + "FAH" + ], + [ + "ITGA2" + ], + [ + "IGFBP2" + ], + [ + "LBP" + ], + [ + "PGAM1;hCG_2015269" + ], + [ + "PAM" + ], + [ + "VCAM1" + ], + [ + "ORM2" + ], + [ + "ITIH1" + ], + [ + "CR2" + ], + [ + "TCN1" + ], + [ + "CD33" + ], + [ + "PGC" + ], + [ + "LMNB1" + ], + [ + "C4BPB" + ], + [ + "AGA" + ], + [ + "FLNA;FLJ00119" + ], + [ + "ACO1;HEL60;IRP1" + ], + [ + "CPN2" + ], + [ + "CES1" + ], + [ + "FBLN1" + ], + [ + "PTPRD" + ], + [ + "PTPRG" + ], + [ + "GPT" + ], + [ + "IGFBP6" + ], + [ + "ATP5A1;HEL-S-123m" + ], + [ + "PSMA1;HEL-S-275" + ], + [ + "MSN;HEL70" + ], + [ + "S100A4" + ], + [ + "MGAT1" + ], + [ + "PON1" + ], + [ + "DPP4" + ], + [ + "CALR;HEL-S-99n" + ], + [ + "CANX" + ], + [ + "PSMB6" + ], + [ + "PSMB5" + ], + [ + "TKT;HEL107" + ], + [ + "MARCKS" + ], + [ + "PRDX6;HEL-S-128m" + ], + [ + "BLVRB;HEL-S-10" + ], + [ + "PRDX5;HEL-S-55" + ], + [ + "AXL" + ], + [ + "S100A7" + ], + [ + "PRDX2;HEL-S-2a" + ], + [ + "CDH5" + ], + [ + "MAN1A1" + ], + [ + "THBS4" + ], + [ + "KRT9" + ], + [ + "FBN1" + ], + [ + "TAGLN2" + ], + [ + "GP5" + ], + [ + "CEACAM6;CEA" + ], + [ + "MDH1;HEL-S-32" + ], + [ + "BTD" + ], + [ + "AFM" + ], + [ + "LGALS7" + ], + [ + "MASP1" + ], + [ + "RPIA" + ], + [ + "MAN2A2" + ], + [ + "PSMB3" + ], + [ + "LUM" + ], + [ + "CACNA2D1;WUGSC:H_DJ0560O14.1" + ], + [ + "VCP;HEL-S-70;DKFZp434K0126" + ], + [ + "EIF6" + ], + [ + "INHBE" + ], + [ + "TPI1;HEL-S-49" + ], + [ + "ACTB;PS1TP5BP1;ACTG1" + ], + [ + "YWHAE;HEL2;YWHAE/FAM22B fusion;YWHAE/FAM22A fusion" + ], + [ + "EIF5A;EIF5AL1" + ], + [ + "TPM4;HEL-S-108" + ], + [ + "EEF1A1;EEF1A1P5;EEF1A1L14" + ], + [ + "HIST1H3A" + ], + [ + "SIRPA;PTPNS1" + ], + [ + "IL13RA1" + ], + [ + "GPLD1" + ], + [ + "S100A12" + ], + [ + "BASP1" + ], + [ + "MXRA7" + ], + [ + "TAGLN" + ], + [ + "DSG1" + ], + [ + "AKAP12;DKFZp686M0430" + ], + [ + "CFHR3" + ], + [ + "ITIH3" + ], + [ + "PRDX1" + ], + [ + "LRP1" + ], + [ + "TGM3" + ], + [ + "DSC1" + ], + [ + "FGL1" + ], + [ + "SIGLEC14;SIGLEC5" + ], + [ + "AHNAK" + ], + [ + "IGKC" + ], + [ + "STAB1" + ], + [ + "APOBR;APOB48R" + ], + [ + "IGHV3-49" + ], + [ + "FSTL1" + ], + [ + "SPP2" + ], + [ + "MMRN1" + ], + [ + "SELENBP1;HEL-S-134P" + ], + [ + "NME3;c371H6.2" + ], + [ + "ALCAM" + ], + [ + "APOF" + ], + [ + "BLMH" + ], + [ + "DSG2" + ], + [ + "DYNC1H1" + ], + [ + "EBI3" + ], + [ + "HABP2" + ], + [ + "IHH" + ], + [ + "GLDN" + ], + [ + "PON3" + ], + [ + "PVRL1" + ], + [ + "RSU1" + ], + [ + "FCN2" + ], + [ + "CST6" + ], + [ + "EXT1" + ], + [ + "MAN2A1" + ], + [ + "AOC3" + ], + [ + "SCGB3A2;UGRP1" + ], + [ + "NME1-NME2;NME2" + ], + [ + "LGALSL" + ], + [ + "HYDIN" + ], + [ + "EMCN" + ], + [ + "NSFL1C" + ], + [ + "WDR1" + ], + [ + "GKN1;DKFZp666N164;FOV" + ], + [ + "SDK2" + ], + [ + "GCS1" + ], + [ + "HSPA1A;HEL-S-103;HSPA1B" + ], + [ + "DKFZp781M0386" + ], + [ + "IGL@" + ], + [ + "DKFZp686O1553" + ], + [ + "ITLN1;ITLN2" + ], + [ + "MIA3" + ], + [ + "WDR44;DKFZp761M142" + ], + [ + "COLEC12" + ], + [ + "V1-13" + ], + [ + "V2-17" + ], + [ + "V5-6;VLC8;IGLV4-69" + ], + [ + "APOM" + ], + [ + "NANS;HEL-S-100" + ], + [ + "scFv" + ], + [ + "HMFT1766" + ], + [ + "ATF6B" + ], + [ + "VASN" + ], + [ + "IGL@" + ], + [ + "IGH@" + ], + [ + "PM20D1" + ], + [ + "TWF2" + ], + [ + "C2" + ], + [ + "DKFZp686M0562" + ], + [ + "DKFZp686G11190;DKFZp686O01196;DKFZp686H20196" + ], + [ + "DKFZp686C11235" + ], + [ + "DKFZp686M08189" + ], + [ + "DKFZp686P15220" + ], + [ + "DKFZp686I04196;DKFZp686E23209" + ], + [ + "DKFZp686I15196" + ], + [ + "IGL@" + ], + [ + "CASC4" + ], + [ + "IGK@" + ], + [ + "IGK@" + ], + [ + "CSPG4" + ], + [ + "SBSN" + ], + [ + "PI16" + ], + [ + "ADAMTSL4" + ], + [ + "CD109" + ], + [ + "SCARA5" + ], + [ + "QSOX2" + ], + [ + "DKFZp686K18196" + ], + [ + "HIST2H3A" + ], + [ + "ADAMTS13" + ], + [ + "NEGR1" + ], + [ + "MEGF8" + ], + [ + "B3GNT8" + ], + [ + "GPR126" + ], + [ + "SERPINA11" + ], + [ + "OAF" + ], + [ + "FERMT3" + ], + [ + "PKHD1L1" + ], + [ + "LSR" + ], + [ + "TREML1" + ], + [ + "SERPINA12" + ], + [ + "FAM20C" + ], + [ + "IGL@" + ], + [ + "TMEM132C" + ], + [ + "IGL@" + ], + [ + "PCSK9" + ], + [ + "PLA2G15" + ], + [ + "HMCN2" + ], + [ + "FLJ00385" + ], + [ + "SNED1" + ], + [ + "OIT3" + ], + [ + "ST8SIA4" + ], + [ + "SMPDL3A" + ], + [ + "FAM3C" + ], + [ + "NEO1" + ], + [ + "CPB2" + ], + [ + "IGHA1;DKFZp686G21220;SNC73;DKFZp686J11235" + ], + [ + "MEGF10" + ], + [ + "PGLYRP2" + ], + [ + "HMCN1" + ], + [ + "HEL-S-300;PEBP4" + ], + [ + "PARK7;HEL-S-67p" + ], + [ + "OSMR" + ], + [ + "FUCA2" + ], + [ + "COLEC11" + ], + [ + "CHMP4A" + ], + [ + "CDHR2" + ], + [ + "MEGF9" + ], + [ + "ANTXR1;ANTXR1/NNG1 fusion" + ], + [ + "MMRN2" + ], + [ + "ERVMER34-1" + ], + [ + "PARVB" + ], + [ + "SLC38A10" + ], + [ + "PCDH18" + ], + [ + "CD248" + ], + [ + "APMAP" + ], + [ + "MAN1C1" + ], + [ + "MXRA5" + ], + [ + "SEMA3G" + ], + [ + "CBLN4" + ], + [ + "B3GNT2" + ], + [ + "ERAP1;ARTS-1" + ], + [ + "SACS" + ], + [ + "EHD3" + ], + [ + "C1RL" + ], + [ + "CNTN3" + ], + [ + "MRC2" + ], + [ + "FETUB;GUGU" + ], + [ + "PCSK1N" + ], + [ + "PCYOX1" + ], + [ + "CD84" + ], + [ + "PLXNA1" + ], + [ + "DBNL" + ], + [ + "TRHDE" + ], + [ + "HEG1" + ], + [ + "NOTCH3" + ], + [ + "NENF" + ], + [ + "PROCR" + ], + [ + "NUDC;NPD011" + ], + [ + "VSIG4" + ], + [ + "PRG3" + ], + [ + "TLN1" + ], + [ + "PLXND1" + ], + [ + "HYOU1" + ], + [ + "APOB" + ], + [ + "APOA2" + ], + [ + "HEL-214" + ] + ], + "hovertemplate": "color=non_sig
log2fc=%{x}
-log10(p-value)=%{y}
Gene names=%{customdata[0]}", + "legendgroup": "non_sig", + "marker": { + "color": "#404040", + "symbol": "circle" + }, + "mode": "markers", + "name": "non_sig", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": [ + -2.7755575615628914e-17, + 0.333138301576145, + -0.6347075280073481, + -0.42703132129984467, + 0.8342144886462177, + 0, + 0, + 0.9066333225475559, + -2.7755575615628914e-17, + 0.454668589487874, + -1.2587552209292951, + -0.02280949795669549, + 2.7755575615628914e-17, + -0.4112829486895075, + 0.8751899489873668, + 0.5373673861474064, + 0, + -0.700151959189893, + 0.2885592106977906, + -0.36708674076483017, + -2.7755575615628914e-17, + 0, + -0.14906984275958046, + -2.7755575615628914e-17, + 0.8751899489873669, + -0.7001519591898941, + -2.7755575615628914e-17, + -0.7696441387494192, + -0.7001519591898936, + -0.140149489998055, + -0.780278053943932, + -0.23644347943498473, + 0.3295290400374018, + -0.7001519591898937, + 0.14434980325323252, + -0.7001519591898937, + -0.24870521114134808, + 0.11347434143135446, + -2.7755575615628914e-17, + 0, + -0.7001519591898937, + -0.29887966797570625, + -2.7755575615628914e-17, + -0.12518938765337267, + -0.7001519591898941, + -2.7755575615628914e-17, + -0.24510954421802778, + -0.5253516270658707, + 0.5971909731221097, + -0.667713021994215, + 0.5748096666381075, + -2.7755575615628914e-17, + 0.8751899489873665, + -0.19306079305491813, + 0.7060857146379338, + 0, + -0.024214820043831534, + 0.35739284186248776, + -0.3134792254228523, + 0.8751899489873675, + 0.022899737113197982, + 0.4513640697388289, + 0.06977206236068983, + -2.7755575615628914e-17, + -0.24544068235860791, + -0.13085684011222234, + -0.41515956568262624, + 0.0225490473757409, + -2.7755575615628914e-17, + 0.862811559108082, + 1.0011271861924682, + 0, + -0.7001519591898934, + 0.8751899489873672, + -0.41179989199350364, + -0.474959282209439, + -0.07303321770094967, + 0.15971174314404593, + 0.17815176421681536, + -0.7001519591898937, + 0, + -0.959751739848894, + -0.7001519591898938, + -0.9098998033728224, + 0.18994098627089948, + -1.1298641644464547, + -0.33655895693172205, + -0.7342635020396223, + 0.13596291705854227, + -0.4141831703615728, + -0.31413907300641564, + -2.7755575615628914e-17, + -0.0842489783572353, + 0.8751899489873672, + -0.24696420265484506, + 0, + -1.1861850913171543, + -0.7263250783015043, + 0.8751899489873669, + 0.24034347531706207, + -2.7755575615628914e-17, + 0.3278676539663546, + 0, + -0.3617449990455292, + 0.19389293934292479, + 0.018619872363760726, + -0.8037116767969865, + -0.011368500057139297, + -0.41717064344784266, + -0.6229013838009364, + -0.22057685454345213, + -0.6783897334376324, + -5.551115123125783e-17, + -0.7001519591898937, + -0.7001519591898945, + 0.7111519971919171, + -0.8332846751088118, + -2.7755575615628914e-17, + 0, + 0, + 0.30345035015310395, + -2.7755575615628914e-17, + -0.5922414578866084, + -0.13246605777410553, + -1.015391382814563, + -0.1307962639729504, + -0.5254109698351183, + 0, + -0.7386714171772011, + -2.7755575615628914e-17, + -0.3833224982057215, + 0, + -5.551115123125783e-17, + 1.0101178069055545, + 0.026569528168280454, + 0, + 0.21771916490798193, + 0.5281434397801423, + -0.09590539433168041, + 0, + 0.19977711803426834, + -2.7755575615628914e-17, + -0.35176921917677895, + -0.7001519591898939, + -0.6726948968587849, + -2.7755575615628914e-17, + 2.7755575615628914e-17, + 0.05155861082583474, + 0.7171828189058916, + -0.7001519591898937, + 0, + -0.2863836726892395, + -0.7001519591898938, + 0.28391271145168084, + -0.7001519591898936, + 0.0815537126199413, + -0.7597031031494619, + -0.42849189843846874, + 0.023545241232949127, + -0.09795815736070247, + -2.7755575615628914e-17, + -0.3578245159029972, + 0.26120472673377126, + -0.2818865482153186, + 0.8751899489873679, + -2.7755575615628914e-17, + 0.8751899489873665, + 0.8165472002784719, + 0.03020041521186766, + -0.2969810963043287, + -0.3676881706359361, + -0.7154961887249919, + -0.11159257662763725, + -0.5331641341605563, + -2.7755575615628914e-17, + 2.7755575615628914e-17, + -2.7755575615628914e-17, + -0.444990245524436, + -0.14311889121843518, + 0.9989004299829685, + -2.7755575615628914e-17, + -0.163318770380897, + -2.7755575615628914e-17, + -0.41011384295493364, + -2.7755575615628914e-17, + 0.15416565348177863, + 0.46604667403078903, + 0.45823979620786087, + -0.19354694630643876, + 0.011452085321668304, + -0.24124127393229186, + 0.1108797554826303, + -0.2684396365341599, + -0.7001519591898937, + 0, + 0.8751899489873671, + -2.7755575615628914e-17, + -0.1615029514761121, + -0.18406495756497704, + -0.9308353910834268, + -0.3399357256829167, + -0.47632040190600555, + 1.2548312486294595, + -0.34051221745112514, + -0.5804832744255889, + -0.6840817510080985, + -0.23431703534634302, + -2.7755575615628914e-17, + -0.24341597347036953, + 0.8751899489873672, + -0.5659343476613774, + -2.7755575615628914e-17, + -0.7001519591898937, + 0, + -0.15293312517303742, + -0.19674272776965046, + 0.2514193586702382, + 0.610918971680545, + 1.2360336032911399, + 0.5303828768645156, + -0.8589475519168821, + 2.7755575615628914e-17, + 0.09055069201968924, + 0.16737556505177797, + -2.7755575615628914e-17, + -0.9140822093673069, + -0.2222272421578412, + 0.3900380223929991, + 0.8751899489873665, + -0.2522927331562853, + -0.23307730561166307, + -1.3211648552238446, + 2.7755575615628914e-17, + -0.10460726391984898, + 0.2425474546017991, + -0.1889010243280585, + 0.3875008308141697, + -0.05908777882054048, + -0.7001519591898939, + -2.7755575615628914e-17, + 1.0910759638941403, + -2.7755575615628914e-17, + -0.8096079782859678, + 0, + 0.458252048321974, + -0.262008904652298, + 0.6838297594775884, + -0.2609420498799349, + 2.7755575615628914e-17, + 0.3888366508310883, + 0.8944032618555611, + -2.7755575615628914e-17, + 0, + 1.139430593040538, + 0.875189948987368, + 0, + 0, + -0.6998570707468439, + 0.6474829113585645, + -0.27177323316580126, + 0.8044469227318535, + 0.09898336880995665, + -2.7755575615628914e-17, + -0.03281233554610774, + 0.7603912537952513, + -0.14069338275975168, + 0.0791871251960411, + 0.8751899489873673, + -0.22252444644264086, + -0.003237046190648629, + -0.8228955222237272, + 0, + -0.2631801323971069, + 0, + 0.4035465829943806, + 0.1034007598504407, + -0.7001519591898934, + 0.6003461915619632, + -0.32824583617831327, + -0.6039730198920595, + -0.7001519591898935, + -1.0243977985648531, + 0, + -0.10819462286869215, + 0.04088526941595591, + 0.6692854616489696, + -2.7755575615628914e-17, + -0.5840257215105212, + -2.7755575615628914e-17, + -2.7755575615628914e-17, + -0.13817849266445859, + -0.6456494140588324, + 0.8751899489873673, + -2.7755575615628914e-17, + 0, + -0.09827005145362233, + -2.7755575615628914e-17, + 0.13675637361490234, + -0.5535713025803157, + 0, + 0.7112082243287264, + -0.49437411306511586, + 0.32609463377626735, + 0.062369527219201415, + 0, + -0.8039301138981267, + -0.46384765831429536, + -0.0384189592875423, + -0.7001519591898936, + 0.21900975588088903, + 0.8751899489873678, + 0.8751899489873678, + 0.6123118942005578, + -0.7001519591898937, + 0, + -0.7001519591898939, + -0.5942102293352418, + -0.6494060869298623, + -0.5110729385229175, + -2.7755575615628914e-17, + 0.23453174153239195, + 0.875189948987368, + 0.059008746810805146, + 0.05986706493622315, + 0.42659182994050504, + -0.2973027786671249, + 0.5475188666485657, + -0.7001519591898936, + -0.031340128599585126, + 0, + -0.22110163393095994, + 0, + -0.6983990939120144, + -0.19451523796848252, + 0.49906773514196756, + -0.4992757943963123, + 0, + 0.4057708671503986, + 0, + -2.7755575615628914e-17, + -1.015145390024226, + -0.0051787843861659105, + -0.26087767855053445, + 0.17145521396039826, + -0.7784575412280108, + -2.7755575615628914e-17, + 0, + 0.4342623700845394, + 0.31978149020241975, + -2.7755575615628914e-17, + 0, + 0.10532931084906813, + -2.7755575615628914e-17, + 2.7755575615628914e-17, + 0.559205556687355, + -0.4974665588106845, + -0.3997747959569891, + 0.13558674652124156, + 0, + 0.3663830545822198, + 0.8751899489873671, + -0.43086554012813666, + -0.7001519591898933, + 1.087165763236559, + -0.4487763886539353, + 0.5257275122053904, + 0.00048383252381301034, + -0.700943866709578, + 0.8751899489873675, + 2.7755575615628914e-17, + 0.31850375393071206, + -0.7001519591898936, + 0, + 0, + -0.05953557965008377, + 0.08733646319919172, + 0.2764613897831743, + -0.0686822916339285, + -0.9325373874367797, + 0, + -1.1999342718455197, + 0, + 0.43070599512585295, + -0.2945108817865909, + 0, + -0.352389565548581, + -0.6293880656635266, + -0.4205437448428503, + -0.7001519591898939, + -2.7755575615628914e-17, + 1.0150096082473483, + 0.5515690943686219, + -0.21201560386496776, + -0.7001519591898941, + 0, + 0.7274003448550745, + -2.7755575615628914e-17, + 0.028410773756992636, + 0, + -2.7755575615628914e-17, + 2.7755575615628914e-17, + 0.09733444194735308, + 0, + 0.8751899489873679, + -0.7001519591898934, + -0.7001519591898937, + 0.0025343836824183175, + -0.8499701455307689, + 1.1426313346615127, + -0.044213158199536376, + -0.4065511036272442, + 1.2496970792422384, + 0.07178384442702582, + 1.1472349709727445, + -2.7755575615628914e-17, + -2.7755575615628914e-17, + 0.13914903741232743, + -0.321360091246128, + 0.4482960053587943, + -0.09101542538678375, + -0.7001519591898936, + 0.8359477880254037, + -0.10883960907984824, + -2.7755575615628914e-17, + -0.7287244449136352, + 0.05335321545656346, + 0.6188567542140908, + 0.10625206810428692, + 0.4064768936864231, + 0.09001839936485456, + -0.26737105065474825, + 0, + -0.335192807159858, + 0.8751899489873672, + 0.4594848809706644, + -2.7755575615628914e-17, + -0.18351780016542174, + -0.31608911041842824, + 0.13820081349430574, + 0.022968196515299077, + 0.09963514604668501, + 0.593923193602405, + 0.48841892775806484, + -1.044079899691368, + -0.22293610419085166, + -0.7165432510395682, + 0.6168799007947781, + -0.2633704080337834, + 0.5630715829342945, + -2.7755575615628914e-17, + -0.16170167776293054, + -0.006502798855718786, + 0, + 0, + 0, + -0.3325281119352001, + -0.544636390563668, + 0.36632064123715113, + -0.3469857178183172, + 0.1711280478037048, + 0.8751899489873672, + -0.31811601502769976, + -0.38679106071628616, + -0.33817444527841156, + 0.3454745286980261, + 0, + 0.4197076605694276, + 0, + -0.3449145614109128, + 0.30626884839860785, + 0, + 0, + -0.5833501207442022, + 0.3949345673517123, + 0, + -0.3924584533918669, + 0.3827000409855444, + -0.06300335996834372, + 0, + -0.5049954342727093, + -0.18241751188397323, + 0.46240390903817274, + 0.8751899489873672, + -2.7755575615628914e-17, + -0.8820689406591489, + 0, + 0, + -0.3765085351847128, + -0.6920731958618725, + -0.31706021253516936, + -0.17043380434052552, + -0.43570434656340173, + -2.7755575615628914e-17, + 0, + 2.7755575615628914e-17, + 0.473905409806319, + -0.700151959189894, + 0.5626371964367147, + 0.24479062414368835, + -0.700151959189894, + -0.538692741841633, + -0.17965286866563313, + 2.7755575615628914e-17, + -0.42858804693587094, + -0.7001519591898938, + 0.5428879864622882, + 0.8319223816733124, + 0.5765187621223207, + -0.7001519591898937, + 0.24027154318458144, + 0.8751899489873672, + 0.33350463774212824, + -0.6596432016690426, + -2.7755575615628914e-17, + -2.7755575615628914e-17, + -2.7755575615628914e-17, + -0.47437468510833447, + 0, + 0.22443282993351166, + 0, + -0.8366449403450258, + -0.7001519591898936, + -0.8389215779145082, + 0.2323445833779002, + -0.7001519591898939, + -0.7001519591898936, + 0, + 1.0503020386966655, + -0.8244929432590966, + 0.03795009811872071, + 0.44864081952832385, + 0.15958616345319213, + -0.4060129064522928, + -0.9696298186676345, + 0.60850043528564, + -0.05625799877727561, + 0.297612315991827, + -0.006749620748950941, + 0.3366562740824839, + 0.6502873986250464, + 0.25040996444941976, + 0.5407460864759455, + -0.8165851880287037, + 0.6337888059294627, + -0.42227881282541185, + -0.616800480107747, + -0.726277234722313, + -0.35297498264604055, + -0.9294884312913203, + 0.13679605810054307, + 0, + -0.25315028240066184, + -0.2980214421361689, + -0.0383120850132026, + -0.24506262860267902, + 0.9181576315357421, + 0.7675041765199251, + 1.2443569207932539, + -0.38368960103910166, + -0.06412523182080937, + -0.18025759246170567, + -0.7062230511865378, + 0.04248033489012709, + 1.535179125272298, + 0.3468962319201062, + -0.03294617131515026, + 0.4874791755376263, + -0.2779838197996424, + 0.17728806142969716, + -0.12969650475583389, + -0.46560600560102117, + 0.27178359992565226, + 0.35913410482741803, + -0.7577439510082533, + -0.30479507883893786, + -0.5496082546186726, + -0.700151959189894, + 0.7152653411459626, + 0.17102879950155217, + 0.23190322959042803, + -0.9638712974456434, + -0.044918827934694816, + 0, + 0.5020700351264937, + 0.6629381481240273, + 0, + 0.005824082783480344, + -0.14102607314802906, + -0.5725424529883998, + -0.1591076875831991, + -0.6261705072870789, + 0.5011881350565643, + 0.09901444957408428, + -0.2823128420737599, + -2.7755575615628914e-17, + 1.0001042567333231, + -0.11162983004258653, + 0.3872708167654062, + -0.4679728606421756, + -0.50006753093598, + -0.4202988413855037, + 0.6863336217302561, + -0.7001519591898937, + -0.5347477093291312, + -2.7755575615628914e-17, + 0.44914850461616274, + -0.41958024741331046, + 0.15173808136405423, + 0.33043638095798195, + -0.9344797039813686, + -0.3426829268454665, + 1.1372504857360402, + 0, + -0.24460732129592677, + -0.2719260394614889, + 0.43992523116784954, + -0.25606875018405906, + -0.46353136935493355, + -0.5061898268624636, + -0.7001519591898935, + 0.1300319073040612, + 0.5934284870078441, + -0.12658582203926894, + 0.5347668931459428, + -0.3947836340297861, + 0.8213697025040125, + 0.05457499190330195, + 0.31182686907856294, + 0, + -0.5839654932521715, + -2.7755575615628914e-17, + 0.04525780276145481, + -0.010088796123058907, + -0.0393609863526521, + -0.2802437490048623, + 0.6264287396164151, + 0, + 0, + -0.4893447411466954, + -0.0316788923397667, + -0.28343150912558335, + -0.24730178727448507, + -2.7755575615628914e-17, + 0, + 0.23934873928413666, + -2.7755575615628914e-17, + -0.10113393391002018, + -0.3163320389485339, + -2.7755575615628914e-17, + 0, + -0.8603787857623899, + -0.7001519591898937, + 0.5618214665838737, + -0.3381388050984421, + 0.037891417960823626, + -0.2981904015539847, + -0.43965914190872946, + -0.5041024146311458, + 0.7865195590665013, + -0.37852434802955814, + -2.7755575615628914e-17, + 2.7755575615628914e-17, + 0, + 0.8751899489873682, + 0.23516111922338, + 0.5922098469169036, + 0.6154484500330113, + -0.7001519591898936, + 0.3504420387593869, + 0.5532207793839787, + -0.45043906932290606, + -2.7755575615628914e-17, + -0.15754254483766406, + -0.18996343464719986, + -0.3820871792267996, + -2.7755575615628914e-17, + 0.4788056649633608, + 0.26747529700323824, + 0.6363372070170071, + -2.7755575615628914e-17, + 0.43243826917469236, + 0.2910154581829105, + -0.49025897271528385, + -1.0491636082471165, + 0, + -2.7755575615628914e-17, + -0.10095401330831615, + -0.08004129916436836, + -0.1885965892431281, + -0.060088117917946215, + 0.7354680275111248, + 0, + 0.29360536720495733, + -0.6081622189962749, + -0.6373461917459327, + 0.3662690650849123, + -0.30122261433759145, + -0.36670237706985864, + 0.41917869376745787, + -0.12663788187238756, + 0.029087660562974016, + 0.8751899489873672, + 0.16866354082759072, + -0.182914038208561, + -1.3056472693755325, + -0.7001519591898935, + -0.2600954462674373, + -0.4472611071687651, + 0.017857355261444864, + 0.8531943579828585, + -0.4303945012579137, + -0.711519118806426, + 0.2989322821413431, + -0.7001519591898936, + 0.5839113295030786, + 0.02352564388169781, + 1.5687743022717107, + 0.7560815051792532, + 0.6516142403834494, + 0.8902255487545463, + 2.7755575615628914e-17, + -2.7755575615628914e-17, + -2.7755575615628914e-17, + 0, + 0.757680026906456, + -2.7755575615628914e-17, + -0.12733115881670423, + 0, + 0, + -0.521149282834507, + -2.7755575615628914e-17, + 0.7325776230216393, + 0.8111924167004918, + -0.17154201508027492, + -0.1923050535854121, + -2.7755575615628914e-17, + -2.7755575615628914e-17, + -0.09641874105402554, + -0.13131576153443056, + 0.290232262033841, + 0.849309045105036, + -0.7452802584026317, + -0.7001519591898939, + -0.38296278659779254, + 0, + 0.8623460460056313, + -0.7171192702516926, + -0.16035442449810355, + 0, + -0.06721216270598951, + 0.7549223129004488, + -0.04589077284512973, + -0.0012998647676080721, + 0.875189948987368, + -2.7755575615628914e-17, + -0.4190143834258537, + 2.7755575615628914e-17, + 2.7755575615628914e-17, + 0.5624146471382521, + 2.7755575615628914e-17, + -0.060985394779651814, + 0.002268134929794191, + -2.7755575615628914e-17, + -0.43461115454348687, + -0.9640846147124902, + 0.05485737043659876, + 0.6228959863622558, + -0.3430126497006513, + 1.1310931295981093, + 0.1507599718817375, + -2.7755575615628914e-17, + -0.5173045105098831, + 0.07022747635982733, + -2.7755575615628914e-17, + -2.7755575615628914e-17, + 0.875189948987368, + 0, + -0.46416311058811566, + 0.3443233178017119, + -0.2221362477250099, + -0.315568485946956, + -2.7755575615628914e-17, + -2.7755575615628914e-17, + -0.7001519591898939, + 0.8751899489873671, + -0.8109276299392951, + -0.12980482790972647, + -0.9895292855963749, + -0.7001519591898936, + -0.5111905992687855, + 0.4910580519601064, + -2.7755575615628914e-17, + -0.8422202234350122, + 0.007558655953243343, + -0.07891586421197125, + 0.29410926906957596, + -2.7755575615628914e-17, + 0.34460798415337884, + 0, + 0.20179270745102992, + -0.3893859795629002, + 0.33556267834110165, + -0.7001519591898938, + 0.11651515231670545, + -5.551115123125783e-17, + -0.44784411362986376, + 0.8751899489873667, + -0.3028395417968131, + -0.009430844447463213, + 0.7639102236667928, + 0.554976499966404, + 0.5119541704477147, + 0.6240281275600906, + 0.19075826291165088, + -2.7755575615628914e-17, + -0.7001519591898941, + 0.7083299143588792, + -2.7755575615628914e-17, + -0.6099380307250765, + -0.15091280956393055, + -0.07824421586961872, + -0.06728271208138659, + 2.7755575615628914e-17, + 2.7755575615628914e-17, + -0.15055126285832077, + -0.18788475220697717, + -0.05559420124486715, + -2.7755575615628914e-17, + -0.8202036155335194, + -2.7755575615628914e-17, + -0.5129967859474427, + -0.5778826618134827, + -0.5933752011304256, + -0.7628623906228419, + 0.177288780359749, + -2.7755575615628914e-17, + 0.28118068814501374, + -0.15925733044116402, + 2.7755575615628914e-17, + -2.7755575615628914e-17, + -0.7001519591898937, + 2.7755575615628914e-17, + -0.2915929825903741, + 0.1387149459367477, + 0.9070847561250042, + 0.616876339035112, + 0.8751899489873671, + 0.25150915185556916, + 0.2394552726320756, + -0.22491709711982644, + -0.44921326976607484, + -0.8358708930699511, + -0.19637074406954458, + -0.7346770800965754, + -0.007121291554333081, + 0, + 0.8751899489873665, + 0, + 0.618862487230859, + -2.7755575615628914e-17, + 0, + -0.5590735275473309, + 0.17869873776789305, + 0.5646946938012498, + -0.19829731661219396, + 0, + -0.28994743911004855, + -2.7755575615628914e-17, + -2.7755575615628914e-17, + 0.0477490605219375, + -0.0072973755753941855, + 0.8751899489873671, + -2.7755575615628914e-17, + 0.7167290030101566, + -0.08176287708312287, + -0.6585081165087145, + -0.04118348105426872, + 2.7755575615628914e-17, + 0.790163637032554, + -2.7755575615628914e-17, + -0.7286494793446363, + -0.7001519591898936, + 0.6674540404684557, + -0.014599383907896137, + 0.8751899489873676, + 0, + 0.3934834888598992, + -2.7755575615628914e-17, + -0.49817697524762394, + 2.7755575615628914e-17, + 0.26872774265794835, + 0, + -0.4372646446066418, + 1.1783215690540179, + -0.2820462613653598, + -0.8325774237369657 + ], + "xaxis": "x", + "y": [ + 1.772502648797171, + 0.5584403171631568, + 0.71398237389059, + 0.2986726690866729, + 1.3523238435369909, + 0, + null, + 1.5830525576177665, + 1.772502648797171, + 0.5191186304224951, + 1.3304909647170735, + 0.021825097294708176, + 2.0548081810647805, + 0.3317765418473766, + 0.5584403171631565, + 0.3020360990393577, + null, + 0.4120290444779382, + 0.3651535067130724, + 0.5208197811068097, + 1.772502648797171, + 0, + 0.6772211928716574, + 1.772502648797171, + 0.5584403171631565, + 0.4120290444779387, + 1.772502648797171, + 0.6788203993127692, + 0.4120290444779385, + 0.14107687633824972, + 0.8751608049880997, + 0.16975269699576806, + 0.5352070488413662, + 0.4120290444779387, + 0.09827361466494877, + 0.4120290444779387, + 0.4841693098396092, + 0.15659954503418314, + 1.772502648797171, + 0, + 0.4120290444779387, + 0.23262608862585743, + 1.772502648797171, + 0.1279144391267086, + 0.4120290444779387, + 1.772502648797171, + 0.12184463575844935, + 0.6408922205217767, + 0.34806640499259317, + 0.4120290444779387, + 0.5584403171631565, + 1.772502648797171, + 0.5584403171631565, + 0.4120290444779387, + 0.777506390648403, + null, + 0.030321747516524732, + 0.7653280226973672, + 0.2720319785923725, + 0.5584403171631565, + 0.019077956273247498, + 0.4128967924911594, + 0.060568719544942605, + 1.772502648797171, + 0.19895834530441645, + 0.11845866087688706, + 0.6770299744415904, + 0.01217792080332968, + 2.0548081810647805, + 1.2556394365714851, + 1.4947918570160004, + 0, + 0.4120290444779382, + 0.5584403171631565, + 0.4120290444779387, + 0.5639184791784395, + 0.05307418047966634, + 0.17019353649293234, + 0.12480283081441082, + 0.4120290444779387, + 0, + 1.0148763005125199, + 0.4120290444779387, + 1.2756680708618757, + 0.2912116431924025, + 1.5439025258184627, + 0.4120290444779387, + 0.7253504920748457, + 0.07630013869157885, + 0.6819826645984963, + 0.22231429730739033, + 1.772502648797171, + 0.05702326755764528, + 0.5584403171631565, + 1.0105044073553568, + null, + 1.6684651173110971, + 0.6894398447879903, + 0.5584403171631565, + 0.19026582341470388, + 1.772502648797171, + 0.3693456401951218, + 0, + 0.3922909920587333, + 0.12436008776272622, + 0.015365388065605938, + 1.3160781770646441, + 0.01971796541285679, + 0.3893117281103519, + 0.8184765615764111, + 0.23247543833566298, + 1.0187527606260907, + 1.772502648797171, + 0.4120290444779387, + 0.4120290444779385, + 0.5584403171631565, + 0.7220307804411297, + 1.772502648797171, + null, + 0, + 0.2873720649560482, + 1.772502648797171, + 0.5488367794683131, + 0.1838628296102817, + 1.895355923187914, + 0.10051222451748634, + 0.9498219424673876, + null, + 0.4642933973722335, + 1.772502648797171, + 0.2863326559765945, + null, + 1.772502648797171, + 1.338003139901475, + 0.025896578000076068, + null, + 0.1776673426669941, + 0.5584403171631565, + 0.08307688678855757, + 0, + 0.17438891513053834, + 1.772502648797171, + 0.6830587323480147, + 0.4120290444779387, + 0.7998587315048016, + 1.772502648797171, + 1.772502648797171, + 0.036908814053619496, + 0.5584403171631568, + 0.4120290444779387, + null, + 0.6157704718632621, + 0.4120290444779387, + 0.40374368081948653, + 0.4120290444779385, + 0.043668402827837155, + 0.6798273571446015, + 1.0800012219087969, + 0.020722120578101005, + 0.07360502360655681, + 1.772502648797171, + 0.42708620841806116, + 0.6531118798859606, + 0.23484754526125823, + 0.5584403171631565, + 1.772502648797171, + 0.5584403171631565, + 1.2928579388678394, + 0.023976234270533775, + 0.659015928709805, + 0.18800118453816073, + 1.512652944747649, + 0.08767011062913624, + 0.7046172222698832, + 1.772502648797171, + 1.772502648797171, + 2.0548081810647805, + 0.5754677400951668, + 0.0993181693336531, + 1.3178214004337545, + 1.772502648797171, + 0.14608973179068574, + 1.772502648797171, + 0.4508485973364294, + 1.772502648797171, + 0.16849426292328276, + 0.38382174595204865, + 0.24568504836186686, + 0.25272615836836376, + 0.016820086415290297, + 0.4120290444779387, + 0.08091359758859533, + 0.4120290444779387, + 0.4120290444779382, + 0, + 0.5584403171631561, + 1.772502648797171, + 0.11746737278637334, + 0.1626516241999908, + 2.0441650070114923, + 0.3383144952894566, + 0.6532949968696745, + 1.4352778281032268, + 0.26821952700953283, + 1.2526846330320687, + 0.7692719166907915, + 0.20542355133152837, + 1.772502648797171, + 0.3319725744503884, + 0.5584403171631565, + 0.7597451415708086, + 1.772502648797171, + 0.4120290444779385, + 0, + 0.13168817654530635, + 0.2045635092266399, + 0.13535475724576815, + 1.0622650360779216, + 1.5875544229779586, + 0.5584403171631561, + 0.6918745134395803, + 1.772502648797171, + 0.07487921728560873, + 0.16491588303519736, + 1.772502648797171, + 1.1327935583204851, + 0.19319224684425507, + 0.5584403171631568, + 0.5584403171631565, + 0.21542857844302513, + 0.6006840168782742, + 2.1900772895559895, + 1.772502648797171, + 0.04740836340465219, + 0.1218184053872107, + 0.18882796099722374, + 0.23750751089953687, + 0.053267431536038246, + 0.4120290444779387, + 1.772502648797171, + 0.8221258742728669, + 1.772502648797171, + 1.1095520073908332, + null, + 0.9732644626078434, + 0.36260495614197696, + 1.0246503043595374, + 0.4687476547223709, + 1.772502648797171, + 0.39920971070697236, + 1.2452525756683968, + 1.772502648797171, + 0, + 2.210407417046409, + 0.5584403171631565, + null, + null, + 0.4120290444779387, + 0.8124786303503543, + 0.2537571809811994, + 0.7436829269062967, + 0.5584403171631561, + 1.772502648797171, + 0.026230692832497765, + 0.8033571442565315, + 0.1708375135372767, + 0.0698124505715839, + 0.5584403171631565, + 0.17691038796176314, + 0.002408159995127152, + 0.8062500127668661, + 0, + 0.2973025533417469, + 0, + 0.3950920841376282, + 0.0540200393008228, + 0.4120290444779385, + 0.3425295575943639, + 0.4120290444779387, + 1.2792375546251866, + 0.4120290444779385, + 0.9851426394277486, + null, + 0.10354816426419704, + 0.0255767888852444, + 0.5584403171631561, + 1.772502648797171, + 0.4120290444779387, + 1.772502648797171, + 1.772502648797171, + 0.14898219961062878, + 0.958855432190397, + 0.5584403171631561, + 1.772502648797171, + 0, + 0.09557492149793274, + 1.772502648797171, + 0.1755932574603061, + 0.4120290444779387, + 0, + 0.5584403171631568, + 0.6803546820300254, + 0.2223547285808352, + 0.08814257221569514, + null, + 1.541163832986907, + 0.6336457943688482, + 0.03190118605509825, + 0.4120290444779385, + 0.26340680412890277, + 0.5584403171631565, + 0.5584403171631565, + 0.5584403171631568, + 0.4120290444779385, + null, + 0.4120290444779387, + 0.7307347140710099, + 0.6965967100732735, + 0.49613759481774766, + 1.772502648797171, + 0.1812745795455532, + 0.5584403171631565, + 0.04002477671525216, + 0.05436668647214516, + 0.5271729132610209, + 0.232805213007408, + 0.6684546369424317, + 0.4120290444779385, + 0.0239431769293265, + null, + 0.4120290444779387, + 0, + 0.4120290444779385, + 0.4120290444779387, + 0.8019562938896238, + 0.4120290444779387, + 0, + 0.5343690062153755, + null, + 1.772502648797171, + 1.501677731924605, + 0.0065207699721058525, + 0.1536205267608754, + 0.10121876172907236, + 1.054353514096193, + 1.772502648797171, + 0, + 0.5584403171631565, + 0.3531540916599752, + 1.772502648797171, + null, + 0.09469131942323752, + 1.772502648797171, + 1.772502648797171, + 0.731406041516941, + 0.44866553948465543, + 0.3649889004454527, + 0.11680801137189581, + null, + 0.29834311724096696, + 0.5584403171631565, + 0.4120290444779387, + 0.4120290444779385, + 0.7978322086656138, + 0.46496562434093386, + 0.6002015599707803, + 0.00038288655036179263, + 1.0894669318130232, + 0.5584403171631565, + 1.772502648797171, + 0.3033332287541819, + 0.4120290444779385, + null, + 0, + 0.06858504727901657, + 0.5584403171631561, + 0.705800348066916, + 0.04847241384494308, + 1.2381431531577114, + 0, + 1.7966968146521114, + null, + 0.3992584230649667, + 0.2586653512933111, + 0, + 0.32283310081587463, + 0.5780374468652635, + 0.4120290444779392, + 0.4120290444779387, + 1.772502648797171, + 1.2206161034644334, + 0.5584403171631565, + 0.4120290444779387, + 0.4120290444779387, + 0, + 0.5584403171631565, + 1.772502648797171, + 0.050829944388694884, + null, + 1.772502648797171, + 1.772502648797171, + 0.07343957943751818, + null, + 0.5584403171631565, + 0.4120290444779385, + 0.4120290444779382, + 0.0020674192913357767, + 1.009579384875724, + 1.758117235849911, + 0.04009469507865223, + 0.29210292274713, + 0.979143645314905, + 0.0768716212903979, + 1.464069989330201, + 1.772502648797171, + 1.772502648797171, + 0.1104887203022401, + 0.5190249041541364, + 0.42997777912396823, + 0.09938499021480819, + 0.4120290444779385, + 0.7698401966090792, + 0.04942570439242469, + 1.772502648797171, + 0.6352589496428772, + 0.04374475837567519, + 0.871870262183308, + 0.10471464822500687, + 0.2790474473458841, + 0.053564140410216655, + 0.13069636915708083, + null, + 0.4120290444779387, + 0.5584403171631565, + 0.42840660497604893, + 1.772502648797171, + 0.23656914685912425, + 0.42244008621808404, + 0.12443942285170759, + 0.02270475993843944, + 0.0899689999596203, + 0.6504397155134299, + 0.3603847455240687, + 1.1867092330716131, + 0.280725141740902, + 0.5977898572459047, + 0.38070610674229244, + 0.19140979948737202, + 0.5214974245960992, + 1.772502648797171, + 0.4120290444779387, + 0.0040518505447778045, + null, + 0, + 0, + 0.32809780269377486, + 0.5221686483189649, + 0.3479077066772369, + 0.48997181269032664, + 0.23766587947580686, + 0.5584403171631561, + 0.23986639945949265, + 0.6909648069199781, + 0.4120290444779385, + 0.5584403171631565, + 0, + 0.4264874720882146, + 0, + 0.3085569060196193, + 0.2717555521135977, + null, + 0, + 0.8206851607739902, + 0.42830581353690117, + 0, + 0.4120290444779387, + 0.2143884606330767, + 0.04040315579078, + null, + 0.4373897436576555, + 0.4120290444779387, + 0.33945296922805035, + 0.5584403171631561, + 1.772502648797171, + 0.5862364147930308, + 0, + 0, + 0.42601289975779927, + 0.6896140840958982, + 0.2387830937774905, + 0.10910713676531923, + 0.6335515351071874, + 1.772502648797171, + 0, + 1.772502648797171, + 0.6026054834799613, + 0.4120290444779385, + 0.8298821925477022, + 0.42267164886780334, + 0.4120290444779385, + 0.6626977296191381, + 0.14151170402272295, + 2.0548081810647805, + 0.4120290444779387, + 0.4120290444779387, + 0.5584403171631565, + 1.1435195995776501, + 0.4870351949849767, + 0.4120290444779387, + 0.18669063950086587, + 0.5584403171631561, + 0.4357319473026007, + 0.6485468983199322, + 1.772502648797171, + 1.772502648797171, + 1.772502648797171, + 0.6439056682612437, + 0, + 0.15787553848700908, + 0, + 0.6725687791579598, + 0.4120290444779387, + 1.9936143307610854, + 0.5584403171631561, + 0.4120290444779387, + 0.4120290444779385, + 0, + 1.4298939037386855, + 0.9263560998387593, + 0.022821260706765354, + 0.3614471997815744, + 0.17413686998372319, + 0.34282165281923405, + 0.7464526521205139, + 0.5584403171631565, + 0.4120290444779387, + 0.22009342290013761, + 0.0217455961444494, + 0.5584403171631561, + 1.046201542343886, + 0.17618865134588912, + 0.7448517925564766, + 1.0741514880385703, + 0.6566000196152748, + 0.3612043149735442, + 1.3789259743733422, + 1.454843796280168, + 0.29329362838856854, + 1.3647765806821972, + 0.10453316374354192, + 0, + 0.8822896696123391, + 0.19315092732684958, + 0.06140385896079023, + 0.4120290444779387, + 1.53779237208644, + 0.9275523467185922, + 1.648756525024872, + 1.5754040542423766, + 0.05559447876025973, + 0.4120290444779387, + 0.8493509165444292, + 0.027327507942266075, + 2.1575416925491417, + 0.3319835656914051, + 0.028732884233824984, + 0.4016050779158042, + 0.28301494401034094, + 0.15014508248920402, + 0.11843711483397956, + 0.5381414892054246, + 0.2693988114536022, + 0.3552575820459612, + 1.6846710795576914, + 0.3106991058952449, + 0.36242312655075887, + 0.4120290444779387, + 0.9916424607443203, + 0.13033667879248062, + 0.37942070547690226, + 1.389398896282065, + 0.023841627071308946, + 0, + 0.40423444251454893, + 0.5584403171631561, + 0, + 0.005105780045550455, + 0.09341311482627175, + 0.5816897131428083, + 0.1031366051005015, + 0.3708139410836063, + 0.7596170336513876, + 0.07388028684145796, + 0.32856442568024885, + 1.772502648797171, + 1.0645830006717356, + 0.09933817941888032, + 0.31593169281801275, + 0.4120290444779387, + 0.4866042268843914, + 0.5050860658028641, + 0.5878827581366635, + 0.4120290444779387, + 0.4120290444779387, + 1.772502648797171, + 0.2616135940286416, + 0.4120290444779387, + 0.11572038842594433, + 0.2666754697652606, + 1.2338294910398173, + 0.3715010579345843, + 1.317714105641006, + 0, + 0.18337069250530608, + 0.4120290444779387, + 0.30180551287816837, + 0.20969021305088012, + 0.5211532231866561, + 0.7556874218558457, + 0.4120290444779385, + 0.20754426334273507, + 0.5297819457907247, + 0.09583871471152694, + 0.7380375090654077, + 0.29546805606599347, + 1.1117220235198852, + 0.05126027258376697, + 0.2214835734942048, + null, + 0.4120290444779387, + 1.772502648797171, + 0.07193752800078486, + 0.007269726724201475, + 0.024778893632039847, + 0.16746491516877024, + 1.065476163841233, + 0, + 0, + 0.7627475765434323, + 0.025520582665410418, + 0.17441035590435786, + 0.21853523865524435, + 1.772502648797171, + 0, + 0.17408414082520918, + 1.772502648797171, + 0.09152231844085693, + 0.41933011400100184, + 1.772502648797171, + 0, + 1.0381127257195062, + 0.4120290444779385, + 0.5584403171631565, + 0.2594593919591488, + 0.032527568002005534, + 0.44186630790522186, + 0.3697778830695373, + 0.6185379881980735, + 1.2105344390740091, + 0.2302861739305022, + 1.772502648797171, + 1.772502648797171, + null, + 0.5584403171631565, + 0.15653094493254568, + 0.5584403171631565, + 0.5431035205301998, + 0.4120290444779385, + 0.3135122807405431, + 0.5271063595558663, + 0.6131688634552811, + 1.772502648797171, + 0.1548276557962718, + 0.20252123320481147, + 0.2878632170470528, + 1.772502648797171, + 0.43160928518338787, + 0.3182810211554076, + 0.5584403171631565, + 1.772502648797171, + 0.3379975377777614, + 0.24253083599678127, + 0.636409529397834, + 0.9059265883879971, + null, + 1.772502648797171, + 0.08692093180001492, + 0.044835476961009986, + 0.1184004090395517, + 0.06131793471123803, + 0.9475237459414951, + 0, + 0.2407599530552776, + 0.6720229370086492, + 1.063503345845754, + 0.3141153327127686, + 0.3052687931418672, + 0.315024132490435, + 0.4039015572559909, + 0.06854749930943499, + 0.01552112624434785, + 0.5584403171631565, + 0.08020756102347876, + 0.1261065570724652, + 2.3686101927983048, + 0.4120290444779387, + 0.2514632726097881, + 0.4120290444779387, + 0.0150448085208336, + 0.5584403171631565, + 0.4539915969069484, + 0.7905571157379734, + 0.17450092282174237, + 0.4120290444779385, + 0.5584403171631565, + 0.01546232961480669, + 2.18721375451002, + 0.5584403171631568, + 0.5584403171631565, + 0.7166219153097478, + 1.772502648797171, + 1.772502648797171, + 1.772502648797171, + null, + 2.264783603923496, + 1.772502648797171, + 0.4120290444779387, + 0, + null, + 0.7288109716354739, + 1.772502648797171, + 0.5680773726296533, + 0.8202626142229654, + 0.4120290444779387, + 0.1451446356390148, + 1.772502648797171, + 1.772502648797171, + 0.05800158939103907, + 0.17784062438488013, + 0.2082016215745499, + 1.2790911864807641, + 0.7333439617737766, + 0.4120290444779387, + 0.4729310061116854, + 0, + 0.9684593406504006, + 0.9337498872819661, + 0.1252029774917221, + 0, + 0.11151596249232267, + 0.8588245198160964, + 0.029836284591220508, + 0.0016144381452957508, + 0.5584403171631565, + 1.772502648797171, + 0.5913560839590779, + 1.772502648797171, + 1.772502648797171, + 0.5651973549845237, + 1.772502648797171, + 0.06605253117419516, + 0.0013678744117717318, + 1.772502648797171, + 0.6410251016272102, + 1.2850756002678465, + 0.040472590502160864, + 0.5584403171631561, + 0.6872734145346991, + 0.8776332866111798, + 0.3332703443348623, + 1.772502648797171, + 0.9472938418927374, + 0.0546457070447146, + 1.772502648797171, + 1.772502648797171, + 0.5584403171631565, + null, + 0.651059461154663, + 0.2653733852195972, + 0.17517662033987227, + 0.4120290444779387, + 1.772502648797171, + 1.772502648797171, + 0.4120290444779387, + 0.5584403171631565, + 1.0313708965111104, + 0.07463226364117456, + 0.6841376155646433, + 0.4120290444779387, + 0.48213535293352455, + 1.3445529983240527, + 1.772502648797171, + 1.0936378119901133, + 0.007252135298103277, + 0.08098571314484405, + 0.5584403171631568, + 1.772502648797171, + 0.5584403171631561, + null, + 0.18439993802116417, + 0.4296554669947257, + 0.310890140874846, + 0.4120290444779387, + 0.10275422238491667, + 1.772502648797171, + 0.47382408438474755, + 0.5584403171631561, + 0.2673361017116679, + 0.006755791503911821, + 0.4908428417126096, + 0.7906464599686414, + 0.5498767571722137, + 0.3596512318989383, + 0.18553942491972192, + 1.772502648797171, + 0.4120290444779387, + 0.8195409168870871, + 1.772502648797171, + 1.0024126718766786, + 0.4120290444779387, + 0.06238731777885815, + 0.06726231184498559, + 1.772502648797171, + 1.772502648797171, + 0.4120290444779387, + 0.15083497227668, + 0.050887580431558374, + 1.772502648797171, + 0.6073796477390428, + 1.772502648797171, + 0.33284876478730757, + 0.7707044286915831, + 0.4120290444779387, + 0.8747189481217931, + 0.1566613715520872, + 1.772502648797171, + 0.22480282466368118, + 0.273600491162252, + 2.0548081810647805, + 1.772502648797171, + 0.4120290444779387, + 1.772502648797171, + 0.24057394100008797, + 0.1381735905921995, + 1.6080636991078299, + 0.6895410918641114, + 0.5584403171631561, + 0.31013847948673884, + 0.5584403171631565, + 0.4120290444779385, + 0.3260252756453617, + 0.6939804386592172, + 0.4120290444779387, + 0.6453032796579689, + 0.004412714618914723, + 0, + 0.5584403171631565, + null, + 0.5584403171631565, + 1.772502648797171, + 0, + 0.9724365357908263, + 0.5584403171631565, + 0.7343282128972396, + 0.16015363708057956, + 0, + 0.4120290444779387, + 1.772502648797171, + 1.772502648797171, + 0.12166535458552878, + 0.004430236916097331, + 0.5584403171631561, + 1.772502648797171, + 0.7604265803368351, + 0.05715111995419806, + 0.6965950710821153, + 0.023885055191445285, + 1.772502648797171, + 0.9109772706877587, + 1.772502648797171, + 0.6837492730014183, + 0.4120290444779385, + 0.5584403171631568, + 0.010193891074898409, + 0.5584403171631565, + 0, + 0.2810363453620528, + 1.772502648797171, + 0.4120290444779387, + 1.772502648797171, + 0.32325511282185426, + 0, + 1.215670798638877, + 0.9253367604500625, + 0.2513638365696126, + 1.4251383360705878 + ], + "yaxis": "y" + }, + { + "customdata": [ + [ + "SERPINC1" + ], + [ + "APOM" + ] + ], + "hovertemplate": "color=up
log2fc=%{x}
-log10(p-value)=%{y}
Gene names=%{customdata[0]}", + "legendgroup": "up", + "marker": { + "color": "#B65EAF", + "symbol": "circle" + }, + "mode": "markers", + "name": "up", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": [ + 1.181220478039138, + 1.2825805789376683 + ], + "xaxis": "x", + "y": [ + 3.028320229036027, + 3.301511663141801 + ], + "yaxis": "y" + }, + { + "customdata": [ + [ + "LGALS3BP" + ] + ], + "hovertemplate": "color=down
log2fc=%{x}
-log10(p-value)=%{y}
Gene names=%{customdata[0]}", + "legendgroup": "down", + "marker": { + "color": "#009599", + "symbol": "circle" + }, + "mode": "markers", + "name": "down", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": [ + -1.0539348099152275 + ], + "xaxis": "x", + "y": [ + 3.561179284496835 + ], + "yaxis": "y" + }, + { + "line": { + "color": "black", + "shape": "spline" + }, + "showlegend": false, + "type": "scatter", + "x": [ + 0.19609678778396383, + 0.20394065929532237, + 0.21178453080668094, + 0.21962840231803948, + 0.22747227382939805, + 0.2353161453407566, + 0.24316001685211516, + 0.2510038883634737, + 0.2588477598748323, + 0.2666916313861908, + 0.27453550289754935, + 0.2823793744089079, + 0.2902232459202665, + 0.298067117431625, + 0.3059109889429836, + 0.31375486045434214, + 0.32159873196570066, + 0.3294426034770592, + 0.3372864749884178, + 0.34513034649977636, + 0.3529742180111349, + 0.36081808952249345, + 0.368661961033852, + 0.37650583254521053, + 0.3843497040565691, + 0.39219357556792767, + 0.40003744707928623, + 0.40788131859064475, + 0.4157251901020033, + 0.4235690616133619, + 0.43141293312472045, + 0.43925680463607897, + 0.44710067614743754, + 0.4549445476587961, + 0.4627884191701546, + 0.4706322906815132, + 0.47847616219287176, + 0.4863200337042303, + 0.49416390521558884, + 0.5020077767269474, + 0.509851648238306, + 0.5176955197496645, + 0.5255393912610231, + 0.5333832627723816, + 0.5412271342837401, + 0.5490710057950987, + 0.5569148773064573, + 0.5647587488178158, + 0.5726026203291744, + 0.580446491840533, + 0.5882903633518914, + 0.59613423486325, + 0.6039781063746086, + 0.6118219778859671, + 0.6196658493973257, + 0.6275097209086843, + 0.6353535924200429, + 0.6431974639314013, + 0.6510413354427599, + 0.6588852069541185, + 0.666729078465477, + 0.6745729499768356, + 0.6824168214881942, + 0.6902606929995527, + 0.6981045645109112, + 0.7059484360222698, + 0.7137923075336283, + 0.7216361790449869, + 0.7294800505563455, + 0.737323922067704, + 0.7451677935790626, + 0.7530116650904211, + 0.7608555366017796, + 0.7686994081131382, + 0.7765432796244968, + 0.7843871511358553, + 0.7922310226472139, + 0.8000748941585725, + 0.807918765669931, + 0.8157626371812895, + 0.8236065086926481, + 0.8314503802040066, + 0.8392942517153652, + 0.8471381232267238, + 0.8549819947380823, + 0.8628258662494409, + 0.8706697377607994, + 0.8785136092721579, + 0.8863574807835165, + 0.8942013522948751, + 0.9020452238062336, + 0.9098890953175922, + 0.9177329668289508, + 0.9255768383403092, + 0.9334207098516678, + 0.9412645813630264, + 0.949108452874385, + 0.9569523243857435, + 0.9647961958971021, + 0.9726400674084607, + 0.9804839389198191, + 0.9883278104311777, + 0.9961716819425362, + 1.0040155534538948, + 1.0118594249652533, + 1.019703296476612, + 1.0275471679879704, + 1.035391039499329, + 1.0432349110106875, + 1.0510787825220462, + 1.0589226540334047, + 1.0667665255447631, + 1.0746103970561218, + 1.0824542685674803, + 1.090298140078839, + 1.0981420115901974, + 1.105985883101556, + 1.1138297546129146, + 1.121673626124273, + 1.1295174976356317, + 1.1373613691469902, + 1.1452052406583488, + 1.1530491121697073, + 1.160892983681066, + 1.1687368551924244, + 1.1765807267037829, + 1.1844245982151416, + 1.1922684697265, + 1.2001123412378587, + 1.2079562127492172, + 1.2158000842605758, + 1.2236439557719343, + 1.2314878272832928, + 1.2393316987946514, + 1.24717557030601, + 1.2550194418173686, + 1.262863313328727, + 1.2707071848400857, + 1.2785510563514442, + 1.2863949278628026, + 1.2942387993741613, + 1.3020826708855198, + 1.3099265423968784, + 1.317770413908237, + 1.3256142854195956, + 1.333458156930954, + 1.3413020284423125, + 1.3491458999536712, + 1.3569897714650296, + 1.3648336429763883, + 1.3726775144877468, + 1.3805213859991055, + 1.388365257510464, + 1.3962091290218224, + 1.404053000533181, + 1.4118968720445395, + 1.4197407435558982, + 1.4275846150672566, + 1.4354284865786153, + 1.4432723580899738, + 1.4511162296013322, + 1.458960101112691, + 1.4668039726240494, + 1.474647844135408, + 1.4824917156467665, + 1.4903355871581252, + 1.4981794586694837, + 1.5060233301808421, + 1.5138672016922008, + 1.5217110732035593, + 1.529554944714918, + 1.5373988162262764, + 1.545242687737635, + 1.5530865592489935, + 1.5609304307603522 + ], + "y": [ + null, + 14.097257273759736, + 12.403139772218129, + 11.156229211561971, + 10.188081745676973, + 9.410055172009216, + 8.769073509465146, + 8.23091346036903, + 8.422333778442313, + 7.954883782823797, + 7.550950811844871, + 7.198340170390295, + 6.887852145451513, + 6.6123943341770905, + 6.366398779463046, + 6.145426303813244, + 5.945890240748477, + 5.764858851805389, + 5.599911052709714, + 5.723886628230442, + 5.568667851428426, + 5.426076149999303, + 5.294657200796771, + 5.173170353053175, + 5.060550739808918, + 4.95587922106926, + 4.858358316854349, + 4.7672927722933895, + 4.682073740731825, + 4.602165818686601, + 4.69162608940971, + 4.614133246552897, + 4.5411773049437665, + 4.472378238069755, + 4.407396842454616, + 4.345929432471829, + 4.287703339637454, + 4.2324730775359445, + 4.180017060258898, + 4.130134783362958, + 4.0826443931328935, + 4.151998984621707, + 4.105222370196943, + 4.060582373722833, + 4.017938160672151, + 3.9771608707692687, + 3.9381323815217404, + 3.900744221119378, + 3.8648966101337683, + 3.830497614597076, + 3.797462395697246, + 3.765712543506566, + 3.8221141237665583, + 3.790553206986222, + 3.760172553662698, + 3.730908065673428, + 3.7027001565069955, + 3.6754933642026297, + 3.6492360032536797, + 3.623879850970965, + 3.5993798644301624, + 3.575693924574648, + 3.552782604504263, + 3.600210906311351, + 3.5773021319184917, + 3.5551179215806386, + 3.5336248379011828, + 3.512791450843565, + 3.492588190406721, + 3.4729872120160814, + 3.4539622733732243, + 3.435488621644376, + 3.4175428899978524, + 3.4001030025981462, + 3.4409742481412824, + 3.423467531039817, + 3.4064402383503447, + 3.3898731449524284, + 3.3737480315596127, + 3.3580476202300362, + 3.342755514747122, + 3.3278561454525892, + 3.3133347181452675, + 3.2991771667086573, + 3.285370109148439, + 3.3212521403756154, + 3.3073541651494143, + 3.2937916339446, + 3.2805526581483524, + 3.267625900164831, + 3.255000542055023, + 3.242666256284419, + 3.2306131784125056, + 3.218831881580034, + 3.207313352656086, + 3.239626999101807, + 3.2280131153701253, + 3.216652407057988, + 3.2055367539191875, + 3.1946583768817374, + 3.184009820419456, + 3.1735839360018714, + 3.1633738665424107, + 3.1533730317796245, + 3.1435751145252384, + 3.1339740477200695, + 3.163067769303992, + 3.1533730317796245, + 3.1438690988970386, + 3.134550435315081, + 3.125411716384651, + 3.116447818273751, + 3.1076538086391223, + 3.0990249378108574, + 3.0905566304575838, + 3.082244477701861, + 3.0740842296577613, + 3.1005358843075417, + 3.0922871977859545, + 3.0841864572804547, + 3.076229745522099, + 3.0684132815079237, + 3.060733414657343, + 3.053186619264954, + 3.0457694892323244, + 3.038478733063957, + 3.0313111691109467, + 3.024263721048242, + 3.0485094978158584, + 3.0413800767000208, + 3.034368097148916, + 3.0274706995786116, + 3.0206851159841857, + 3.0140086663198686, + 3.007438755049931, + 3.0009728678583607, + 2.9946085685117816, + 2.988343495865278, + 2.9821753610049853, + 3.004552331515919, + 2.9983088678942194, + 2.9921604880345534, + 2.986105049200754, + 2.9801404722283045, + 2.9742647391936727, + 2.968475891186524, + 2.962772026177413, + 2.9571512969770124, + 2.951611909282587, + 2.9461521198065808, + 2.9669260037975596, + 2.9613972394347416, + 2.9559467598421016, + 2.950572923260299, + 2.945274133296068, + 2.9400488373722458, + 2.9348955252411986, + 2.9298127275582195, + 2.9247990145114073, + 2.9198529945069924, + 2.9149733129053206, + 2.9343571984078842, + 2.9294144148064505, + 2.9245370220360263, + 2.919723737786723, + 2.9149733129053206, + 2.9102845303345446, + 2.905656204093181, + 2.9010871782943775, + 2.8965763262007003, + 2.892122549314726, + 2.887724776503397, + 2.9058921018775266, + 2.901436562294121, + 2.8970363326043076 + ] + }, + { + "line": { + "color": "black", + "shape": "spline" + }, + "showlegend": false, + "type": "scatter", + "x": [ + -0.19609678778396383, + -0.20394065929532237, + -0.21178453080668094, + -0.21962840231803948, + -0.22747227382939805, + -0.2353161453407566, + -0.24316001685211516, + -0.2510038883634737, + -0.2588477598748323, + -0.2666916313861908, + -0.27453550289754935, + -0.2823793744089079, + -0.2902232459202665, + -0.298067117431625, + -0.3059109889429836, + -0.31375486045434214, + -0.32159873196570066, + -0.3294426034770592, + -0.3372864749884178, + -0.34513034649977636, + -0.3529742180111349, + -0.36081808952249345, + -0.368661961033852, + -0.37650583254521053, + -0.3843497040565691, + -0.39219357556792767, + -0.40003744707928623, + -0.40788131859064475, + -0.4157251901020033, + -0.4235690616133619, + -0.43141293312472045, + -0.43925680463607897, + -0.44710067614743754, + -0.4549445476587961, + -0.4627884191701546, + -0.4706322906815132, + -0.47847616219287176, + -0.4863200337042303, + -0.49416390521558884, + -0.5020077767269474, + -0.509851648238306, + -0.5176955197496645, + -0.5255393912610231, + -0.5333832627723816, + -0.5412271342837401, + -0.5490710057950987, + -0.5569148773064573, + -0.5647587488178158, + -0.5726026203291744, + -0.580446491840533, + -0.5882903633518914, + -0.59613423486325, + -0.6039781063746086, + -0.6118219778859671, + -0.6196658493973257, + -0.6275097209086843, + -0.6353535924200429, + -0.6431974639314013, + -0.6510413354427599, + -0.6588852069541185, + -0.666729078465477, + -0.6745729499768356, + -0.6824168214881942, + -0.6902606929995527, + -0.6981045645109112, + -0.7059484360222698, + -0.7137923075336283, + -0.7216361790449869, + -0.7294800505563455, + -0.737323922067704, + -0.7451677935790626, + -0.7530116650904211, + -0.7608555366017796, + -0.7686994081131382, + -0.7765432796244968, + -0.7843871511358553, + -0.7922310226472139, + -0.8000748941585725, + -0.807918765669931, + -0.8157626371812895, + -0.8236065086926481, + -0.8314503802040066, + -0.8392942517153652, + -0.8471381232267238, + -0.8549819947380823, + -0.8628258662494409, + -0.8706697377607994, + -0.8785136092721579, + -0.8863574807835165, + -0.8942013522948751, + -0.9020452238062336, + -0.9098890953175922, + -0.9177329668289508, + -0.9255768383403092, + -0.9334207098516678, + -0.9412645813630264, + -0.949108452874385, + -0.9569523243857435, + -0.9647961958971021, + -0.9726400674084607, + -0.9804839389198191, + -0.9883278104311777, + -0.9961716819425362, + -1.0040155534538948, + -1.0118594249652533, + -1.019703296476612, + -1.0275471679879704, + -1.035391039499329, + -1.0432349110106875, + -1.0510787825220462, + -1.0589226540334047, + -1.0667665255447631, + -1.0746103970561218, + -1.0824542685674803, + -1.090298140078839, + -1.0981420115901974, + -1.105985883101556, + -1.1138297546129146, + -1.121673626124273, + -1.1295174976356317, + -1.1373613691469902, + -1.1452052406583488, + -1.1530491121697073, + -1.160892983681066, + -1.1687368551924244, + -1.1765807267037829, + -1.1844245982151416, + -1.1922684697265, + -1.2001123412378587, + -1.2079562127492172, + -1.2158000842605758, + -1.2236439557719343, + -1.2314878272832928, + -1.2393316987946514, + -1.24717557030601, + -1.2550194418173686, + -1.262863313328727, + -1.2707071848400857, + -1.2785510563514442, + -1.2863949278628026, + -1.2942387993741613, + -1.3020826708855198, + -1.3099265423968784, + -1.317770413908237, + -1.3256142854195956, + -1.333458156930954, + -1.3413020284423125, + -1.3491458999536712, + -1.3569897714650296, + -1.3648336429763883, + -1.3726775144877468, + -1.3805213859991055, + -1.388365257510464, + -1.3962091290218224, + -1.404053000533181, + -1.4118968720445395, + -1.4197407435558982, + -1.4275846150672566, + -1.4354284865786153, + -1.4432723580899738, + -1.4511162296013322, + -1.458960101112691, + -1.4668039726240494, + -1.474647844135408, + -1.4824917156467665, + -1.4903355871581252, + -1.4981794586694837, + -1.5060233301808421, + -1.5138672016922008, + -1.5217110732035593, + -1.529554944714918, + -1.5373988162262764, + -1.545242687737635, + -1.5530865592489935, + -1.5609304307603522 + ], + "y": [ + null, + 14.097257273759736, + 12.403139772218129, + 11.156229211561971, + 10.188081745676973, + 9.410055172009216, + 8.769073509465146, + 8.23091346036903, + 8.422333778442313, + 7.954883782823797, + 7.550950811844871, + 7.198340170390295, + 6.887852145451513, + 6.6123943341770905, + 6.366398779463046, + 6.145426303813244, + 5.945890240748477, + 5.764858851805389, + 5.599911052709714, + 5.723886628230442, + 5.568667851428426, + 5.426076149999303, + 5.294657200796771, + 5.173170353053175, + 5.060550739808918, + 4.95587922106926, + 4.858358316854349, + 4.7672927722933895, + 4.682073740731825, + 4.602165818686601, + 4.69162608940971, + 4.614133246552897, + 4.5411773049437665, + 4.472378238069755, + 4.407396842454616, + 4.345929432471829, + 4.287703339637454, + 4.2324730775359445, + 4.180017060258898, + 4.130134783362958, + 4.0826443931328935, + 4.151998984621707, + 4.105222370196943, + 4.060582373722833, + 4.017938160672151, + 3.9771608707692687, + 3.9381323815217404, + 3.900744221119378, + 3.8648966101337683, + 3.830497614597076, + 3.797462395697246, + 3.765712543506566, + 3.8221141237665583, + 3.790553206986222, + 3.760172553662698, + 3.730908065673428, + 3.7027001565069955, + 3.6754933642026297, + 3.6492360032536797, + 3.623879850970965, + 3.5993798644301624, + 3.575693924574648, + 3.552782604504263, + 3.600210906311351, + 3.5773021319184917, + 3.5551179215806386, + 3.5336248379011828, + 3.512791450843565, + 3.492588190406721, + 3.4729872120160814, + 3.4539622733732243, + 3.435488621644376, + 3.4175428899978524, + 3.4001030025981462, + 3.4409742481412824, + 3.423467531039817, + 3.4064402383503447, + 3.3898731449524284, + 3.3737480315596127, + 3.3580476202300362, + 3.342755514747122, + 3.3278561454525892, + 3.3133347181452675, + 3.2991771667086573, + 3.285370109148439, + 3.3212521403756154, + 3.3073541651494143, + 3.2937916339446, + 3.2805526581483524, + 3.267625900164831, + 3.255000542055023, + 3.242666256284419, + 3.2306131784125056, + 3.218831881580034, + 3.207313352656086, + 3.239626999101807, + 3.2280131153701253, + 3.216652407057988, + 3.2055367539191875, + 3.1946583768817374, + 3.184009820419456, + 3.1735839360018714, + 3.1633738665424107, + 3.1533730317796245, + 3.1435751145252384, + 3.1339740477200695, + 3.163067769303992, + 3.1533730317796245, + 3.1438690988970386, + 3.134550435315081, + 3.125411716384651, + 3.116447818273751, + 3.1076538086391223, + 3.0990249378108574, + 3.0905566304575838, + 3.082244477701861, + 3.0740842296577613, + 3.1005358843075417, + 3.0922871977859545, + 3.0841864572804547, + 3.076229745522099, + 3.0684132815079237, + 3.060733414657343, + 3.053186619264954, + 3.0457694892323244, + 3.038478733063957, + 3.0313111691109467, + 3.024263721048242, + 3.0485094978158584, + 3.0413800767000208, + 3.034368097148916, + 3.0274706995786116, + 3.0206851159841857, + 3.0140086663198686, + 3.007438755049931, + 3.0009728678583607, + 2.9946085685117816, + 2.988343495865278, + 2.9821753610049853, + 3.004552331515919, + 2.9983088678942194, + 2.9921604880345534, + 2.986105049200754, + 2.9801404722283045, + 2.9742647391936727, + 2.968475891186524, + 2.962772026177413, + 2.9571512969770124, + 2.951611909282587, + 2.9461521198065808, + 2.9669260037975596, + 2.9613972394347416, + 2.9559467598421016, + 2.950572923260299, + 2.945274133296068, + 2.9400488373722458, + 2.9348955252411986, + 2.9298127275582195, + 2.9247990145114073, + 2.9198529945069924, + 2.9149733129053206, + 2.9343571984078842, + 2.9294144148064505, + 2.9245370220360263, + 2.919723737786723, + 2.9149733129053206, + 2.9102845303345446, + 2.905656204093181, + 2.9010871782943775, + 2.8965763262007003, + 2.892122549314726, + 2.887724776503397, + 2.9058921018775266, + 2.901436562294121, + 2.8970363326043076 + ] + } + ], + "layout": { + "height": 700, + "legend": { + "title": { + "text": "color" + }, + "tracegroupgap": 0 + }, + "margin": { + "t": 60 + }, + "showlegend": false, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "rgb(36,36,36)" + }, + "error_y": { + "color": "rgb(36,36,36)" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "rgb(36,36,36)", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "rgb(36,36,36)" + }, + "baxis": { + "endlinecolor": "rgb(36,36,36)", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "rgb(36,36,36)" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.6 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "rgb(237,237,237)" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "rgb(217,217,217)" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "rgb(103,0,31)" + ], + [ + 0.1, + "rgb(178,24,43)" + ], + [ + 0.2, + "rgb(214,96,77)" + ], + [ + 0.3, + "rgb(244,165,130)" + ], + [ + 0.4, + "rgb(253,219,199)" + ], + [ + 0.5, + "rgb(247,247,247)" + ], + [ + 0.6, + "rgb(209,229,240)" + ], + [ + 0.7, + "rgb(146,197,222)" + ], + [ + 0.8, + "rgb(67,147,195)" + ], + [ + 0.9, + "rgb(33,102,172)" + ], + [ + 1, + "rgb(5,48,97)" + ] + ], + "sequential": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "sequentialminus": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ] + }, + "colorway": [ + "#009599", + "#005358", + "#772173", + "#B65EAF", + "#A73A00", + "#6490C1", + "#FF894F", + "#2B5E8B", + "#A87F32" + ], + "font": { + "color": "rgb(36,36,36)" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "rgba(0,0,0,0)", + "plot_bgcolor": "rgba(0,0,0,0)", + "polar": { + "angularaxis": { + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "rgb(232,232,232)", + "gridwidth": 2, + "linecolor": "rgb(36,36,36)", + "showbackground": true, + "showgrid": false, + "showline": true, + "ticks": "outside", + "zeroline": false, + "zerolinecolor": "rgb(36,36,36)" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "rgb(232,232,232)", + "gridwidth": 2, + "linecolor": "rgb(36,36,36)", + "showbackground": true, + "showgrid": false, + "showline": true, + "ticks": "outside", + "zeroline": false, + "zerolinecolor": "rgb(36,36,36)" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "rgb(232,232,232)", + "gridwidth": 2, + "linecolor": "rgb(36,36,36)", + "showbackground": true, + "showgrid": false, + "showline": true, + "ticks": "outside", + "zeroline": false, + "zerolinecolor": "rgb(36,36,36)" + } + }, + "shapedefaults": { + "fillcolor": "black", + "line": { + "width": 0 + }, + "opacity": 0.3 + }, + "ternary": { + "aaxis": { + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside" + }, + "baxis": { + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside", + "title": { + "standoff": 15 + }, + "zeroline": false, + "zerolinecolor": "rgb(36,36,36)" + }, + "yaxis": { + "automargin": true, + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside", + "title": { + "standoff": 15 + }, + "zeroline": false, + "zerolinecolor": "rgb(36,36,36)" + } + } + }, + "width": 600, + "xaxis": { + "anchor": "y", + "domain": [ + 0, + 1 + ], + "title": { + "text": "log2fc" + } + }, + "yaxis": { + "anchor": "x", + "domain": [ + 0, + 1 + ], + "title": { + "text": "-log10(p-value)" + } + } + } + }, + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "04dce49a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'spline'" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "plot.to_plotly_json()[\"data\"][4].get(\"line\").get(\"shape\")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "7be6e569", + "metadata": {}, + "outputs": [], + "source": [ + "from multicova import functions\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "dbe02e11", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/drq441/opt/anaconda3/lib/python3.9/site-packages/pandas/core/arraylike.py:402: RuntimeWarning:\n", + "\n", + "divide by zero encountered in log2\n", + "\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "edcd19d1352448ff95731572113ee872", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Pandas Apply: 0%| | 0/899 [00:00%{hovertext}

1% FDR=non_sig
log2 fold change=%{x}
-log10(p-value)=%{y}", + "hovertext": [ + "SERPINE1", + "MYH11", + "PSAP", + "CAPZA1", + "PLD3", + "NELL2", + "CNTN1", + "ALDOB", + "GGT1;hCG_2010666;GGT2;GGT3P", + "MB", + "UPB1;DKFZp779O1248", + "YWHAH", + "NPTXR", + "NAGA", + "IGFBP4", + "JUP", + "KRT23", + "PSME3;HEL-S-283", + "VPS13A", + "TJP2", + "RPL17;LOC402695;hCG_24487;RPL17-C18orf32;LOC202789", + "LMAN1", + "SERPINB5", + "CNTN4", + "RPL15;LOC136321", + "DAG1", + "LAMB2", + "CTSB", + "DLAT", + "TMEM25", + "MCAM", + "NRP2;DKFZp686J1169", + "EEF1B2;LOC392793", + "HSPD1", + "BZW1;hCG_2022736", + "IGFBP5", + "ENO1", + "PLOD1", + "LZIC", + "KLK6", + "CYB5R3", + "DAK;TKFC;DKFZp586B1621", + "PRCP", + "ANXA2;HEL-S-270;ANXA2P2", + "RAB11A;RAB11B", + "PKM2;PKM", + "CLN5", + "LGALS3;hCG_22119", + "ACTN1", + "FBLN5", + "WARS", + "MMP2", + "DPEP2", + "MET", + "BPGM", + "ICAM3;hCG_2033729", + "FGFR4", + "ALAD", + "ENG", + "TNC;TNC variant protein", + "SET", + "ADAMTSL2", + "LCN1", + "COL5A1", + "PTGDS", + "P4HB", + "SELL", + "PKP1", + "CHI3L1", + "LAMC1", + "CPQ;PGCP", + "COLEC10", + "ALPL", + "C1QA", + "HEXB", + "VCAN;CSPG2", + "ARHGDIB", + "CORO1C", + "CDH2", + "GALNT1", + "DDR1", + "PLA2G7", + "HSP90AB1", + "IGFBP7", + "SPP1;opn", + "ADH4;HEL-S-4", + "ASL", + "LAMP1", + "BCAM;LU", + "V3-4;IGLV8-61", + "V5-4;IGLV4-60", + "V2-6;IGLV3-9", + "IGHV4-4", + "IGKV2-24;IGKV2D-24", + "PTPRC", + "NUCB2;HEL-S-109;Nucb2", + "UCHL3", + "NCAM1", + "PTPRJ", + "ROBO1", + "MYCBP", + "OSCAR", + "PRSS1;PRSS3P2", + "TNXB", + "LAMA2", + "ST3GAL6", + "CDH1", + "SEZ6L2;PSK-1", + "UGP2", + "EIF3H;EIF3S3", + "FCGR3B;Fc-gamma receptor IIIB", + "CADM1", + "COL15A1", + "CHL1", + "COL6A1", + "NOMO2;NOMO1;NOMO3", + "NEB", + "PSME2", + "AGRN", + "CNN2", + "PDIA4;ERP70", + "C21orf33", + "CACHD1", + "APP", + "PDE4DIP;CDK5RAP2;DKFZp686M1993", + "SVEP1", + "PLS3", + "RGMA", + "TTN", + "IL6ST", + "CNTFR", + "HPD", + "V5-2;IGLV9-49", + "IGHV3-72", + "SRSF7;SRSF3;SFRS3", + "LYZ", + "IGKV1D-13", + "COL11A2", + "SELPLG", + "CES3", + "GP1BA", + "IGKV6-21", + "IGHV1-3;IGHM", + "IGHV3-38", + "IGKV1-8;IGKV1-9", + "FAP", + "NTRK3", + "LRRFIP1", + "HLA-DRA;HLA-DRA1;HLA-DQA1/DRA", + "LILRA2", + "LILRA6;LILRB3", + "CDHR5;MUPCDH", + "LILRB5;FLJ00275", + "LILRA3", + "PRB4", + "V4-2;IGLV5-45", + "TPM1", + "PSMA7", + "PSME1", + "FGFR1", + "EFEMP1", + "MYOC", + "PCK2", + "NPM1", + "DKFZp686J1372;TPM3", + "HEL-S-82p;TPM3", + "CFP", + "KIT", + "MYH9", + "ART4;DO", + "NAGLU;ufHSD2", + "DPEP1", + "ESD", + "FGG;DKFZp779N0926", + "GSTA2;GSTA1;GSTalpha locus;GSTA3;GSTA5", + "HPRT1", + "KCTD12", + "PEPD", + "SOD3", + "STMN1", + "LCAT", + "LTA4H", + "PSMA3", + "PSMB4", + "TALDO1", + "CALD1", + "ST13;ST13P5;ST13P4", + "ISLR", + "LTF;HEL110", + "ACHE", + "V2-13;VL4", + "CTSD;HEL-S-130P", + "FAS;CD95;TNFRSF6", + "KRT83;KRT86;KRT81;KRT87P", + "HBD", + "V3", + "F5-20", + "KRT13", + "MSTN;GDF8", + "SSC5D", + "RPS6", + "A30", + "VK3", + "IGH@", + "CSF1R", + "GNPTG;RJD9", + "F7", + "ATP6V1F", + "CPA4", + "PCOLCE", + "RPS4X;RPS4Y1;RPS4Y2", + "ANTXR2", + "PDCD1LG2;PDL2", + "GGT7", + "APOL1", + "APOC4", + "BST1", + "BGN", + "IGFBP3", + "B2M", + "PCDH9", + "ANGPTL3", + "GPR116", + "PCDH1", + "OLFM1", + "L1CAM", + "LEPR", + "PSMC4", + "C1S", + "DSC2;DKFZp686P18250;DKFZp686I11137", + "EPHA1", + "EGFR", + "GSPT1;GSPT2", + "GGH", + "COMP", + "ACTC1;ACTA1", + "SECTM1", + "PHB;HEL-S-54e", + "UBE2I", + "C1QBP", + "ADIPOQ", + "UBC;UBB;RPS27A;UBA52;HEL112;DKFZp434K0435;UbC", + "STIP1;HEL-S-94n", + "MAN2B1", + "MANBA", + "IL1RAP", + "REG1A;REG1B", + "NUCB1", + "LMAN2", + "G6PD", + "CDSN;S", + "ELTD1", + "ENPEP", + "SEZ6L", + "FBLN1", + "PSMD10", + "CD58", + "CASP14", + "HIST1H4A;HIST1H4H", + "DKFZp686H17246", + "IDH1;HEL-S-26;HEL-216", + "APLP1", + "LYVE1;XLKD1", + "GUSB", + "ERAP2", + "CDH17", + "MINPP1", + "OMD", + "BPIFB1", + "GSTO1;HEL-S-21", + "CFHR5", + "KIAA0319L", + "CTBS", + "INHBC", + "PCDH12", + "BHMT;HEL-S-61p", + "LSAMP", + "SPARC", + "CALM1;CALM3;CALM2", + "MERTK", + "ITIH4;DKFZp686G21125", + "LCN2;NGAL", + "SNX2;SNX1", + "YWHAG", + "GOLM1;GOLPH2", + "TUBA1B;TUBA1A", + "CALU", + "PDIA3;HEL-S-269", + "PVR", + "FSCN1", + "SIRPB2", + "UMOD", + "CHL1", + "TNN", + "C1QTNF3;C1QTNF3-AMACR", + "HADHA", + "PGM1", + "HSPA4;HEL-S-5a", + "C16orf46", + "SUSD5", + "GANAB;HEL-S-164nA", + "GART", + "PRKCSH", + "CRLF3", + "ECM2", + "GALNT6", + "GDI2", + "PROC", + "INPP5D", + "NCSTN", + "KRT4", + "CD93", + "HAGH", + "SPINT1", + "PSMD11", + "TIE1;TIE", + "ITGA1", + "IVL", + "HEXA", + "GAS6", + "ITGB2", + "PTPRM", + "GRN", + "LAMP2", + "SLC3A2", + "CTSA;PPGB", + "DPP3;DKFZp686O1117", + "CLSTN1", + "CECR1", + "EIF2S2", + "SSB", + "TCN2", + "ESRRG;ESRRB;NR3B3;ERRgamma", + "HBG2;HBG1", + "CCT7", + "TUBA1C", + "CCT4", + "MAN2B2", + "CAST", + "POMGNT1", + "DCBLD2", + "CDH13", + "RTN4RL2", + "PTMA;PTMAP7", + "MRC1;MRC1L1", + "IGFBP1", + "TGFBI", + "C1S", + "CD163", + "SEMA3F", + "NRCAM", + "DMKN", + "KRT75", + "KRT14", + "KRT16", + "KRT10", + "KRT5", + "KRT2", + "FLG2", + "KRT80", + "KRT78", + "KRT25", + "HRNR", + "KRTHB2;KRT82", + "YWHAZ", + "FGG", + "SH3BGRL3;HEL-S-297", + "CAP1", + "DKFZp686P17171;SERBP1", + "EXT2", + "GLIPR2;C9orf19", + "COL18A1", + "ICAM2", + "ABI3BP", + "HGFAC", + "LECT2", + "GC", + "CDH6", + "COL12A1", + "CCDC88A;KIAA1212", + "SFTPB", + "PTPRS", + "PEBP1;HEL-S-34", + "SHH", + "PRAP1", + "SLC4A1", + "TBCA", + "FABP5", + "SNCA;NACP", + "EZR;HEL-S-105;EZR-ROS1", + "ENPP2", + "LTBP1", + "PIEZO2", + "KLKB1", + "FLT4;VEGFR3", + "CR1", + "NRP1;DKFZp781F1414;DKFZp686A03134", + "CFL1;HEL-S-15", + "HLA-A;HLA;MHC class I HLA-A;HLA-A*02;HLA-A2;HLA-B;HLA-A*0225", + "WFDC3", + "PHB2", + "GPR133;ADGRD1", + "PTPRB;DKFZp686E13109;DKFZp686E2262;DKFZp686H15164", + "CDH19", + "GOLIM4", + "TGOLN2", + "SERPINA3", + "LAMB1", + "MST1", + "CDON", + "B2M", + "MSLN", + "CD86", + "CAMP", + "MYL6", + "SEMA4B;DKFZp686A04130", + "RELN", + "GSDMA", + "TPM4", + "TPM4", + "CILP2", + "HSP90AA1;EL52", + "VWF", + "C3", + "ECH1", + "PDLIM1;HEL-S-112", + "MASP2", + "SIRPB1", + "PGRMC1", + "CLIC1", + "FCN1;DKFZp781B1032", + "PLXNB2", + "PLXNB1", + "TREH", + "RGS10", + "CD5L", + "XPNPEP2", + "FIGF", + "SEMA7A", + "CILP", + "PDCD6", + "PAPLN", + "H6PD", + "VNN1", + "LDHA;HEL-S-133P", + "ALDH1A1;HEL-S-53e;HEL-9", + "GSR;HEL-75", + "F8", + "PNP;HEL-S-156an", + "PGK1;HEL-S-68p", + "CA2;HEL-76", + "CSTA", + "PIGR", + "COL3A1", + "LMNA", + "CRP", + "LRG1", + "GC;HEL-S-51", + "PPBP", + "TFRC", + "TF", + "FTL;FTL variant", + "ANG;RAA1", + "FUCA1", + "ALDOA;HEL-S-87p", + "CSTB", + "ANXA1", + "GAPDH;HEL-S-162eP", + "HSPB1;HEL-S-102", + "CHGB", + "ARG1", + "S100A8", + "ICAM1", + "ITGB1", + "C2", + "S100A9", + "S100A6", + "LDHB", + "ASGR2;HBXBP", + "TUBB;XTP3TPATP1", + "CA3;HEL-S-167mP", + "PFN1", + "EPRS", + "THBS1", + "RNASE1;RAC1", + "LPA", + "VIM;HEL113", + "ANXA5;HEL-S-7", + "LGALS1", + "PDGFRB", + "SAA1", + "SAA2", + "PTPRF;LAR", + "CHGA", + "HSPA8;HEL-S-72p", + "MBL2", + "IGF2R", + "COL6A2", + "PIP", + "FCGR2A;FCGR2C;FCGR2B", + "ACE", + "MYH7;MYH6", + "NCAM1", + "EEF2", + "CEACAM1", + "PRG2", + "CD99", + "NID1", + "PKM;HEL-S-30;PKM2", + "IDE", + "CPA1", + "ST6GAL1", + "CD44", + "PNLIP", + "PECAM1", + "FAH", + "ITGA2", + "IGFBP2", + "PGAM1;hCG_2015269", + "PAM", + "CR2", + "TCN1", + "CD33", + "PGC", + "LMNB1", + "C4BPB", + "AGA", + "ACO1;HEL60;IRP1", + "CES1", + "PTPRD", + "PTPRG", + "GPT", + "IGFBP6", + "ATP5A1;HEL-S-123m", + "PSMA1;HEL-S-275", + "MSN;HEL70", + "S100A4", + "MGAT1", + "DPP4", + "CALR;HEL-S-99n", + "CANX", + "PSMB6", + "PSMB5", + "TKT;HEL107", + "MARCKS", + "PRDX6;HEL-S-128m", + "BLVRB;HEL-S-10", + "PRDX5;HEL-S-55", + "AXL", + "S100A7", + "PRDX2;HEL-S-2a", + "MAN1A1", + "THBS4", + "FBN1", + "TAGLN2", + "GP5", + "CEACAM6;CEA", + "MDH1;HEL-S-32", + "LGALS7", + "RPIA", + "MAN2A2", + "PSMB3", + "CACNA2D1;WUGSC:H_DJ0560O14.1", + "VCP;HEL-S-70;DKFZp434K0126", + "EIF6", + "INHBE", + "TPI1;HEL-S-49", + "YWHAE;HEL2;YWHAE/FAM22B fusion;YWHAE/FAM22A fusion", + "EIF5A;EIF5AL1", + "TPM4;HEL-S-108", + "EEF1A1;EEF1A1P5;EEF1A1L14", + "HIST1H3A", + "SIRPA;PTPNS1", + "IL13RA1", + "S100A12", + "BASP1", + "MXRA7", + "TAGLN", + "DSG1", + "AKAP12;DKFZp686M0430", + "CFHR3", + "PRDX1", + "TGM3", + "DSC1", + "FGL1", + "SIGLEC14;SIGLEC5", + "AHNAK", + "STAB1", + "APOBR;APOB48R", + "IGHV3-49", + "FSTL1", + "SPP2", + "MMRN1", + "SELENBP1;HEL-S-134P", + "NME3;c371H6.2", + "ALCAM", + "APOF", + "BLMH", + "DSG2", + "DYNC1H1", + "EBI3", + "IHH", + "GLDN", + "PON3", + "PVRL1", + "RSU1", + "FCN2", + "CST6", + "EXT1", + "MAN2A1", + "AOC3", + "SCGB3A2;UGRP1", + "NME1-NME2;NME2", + "LGALSL", + "HYDIN", + "EMCN", + "NSFL1C", + "WDR1", + "GKN1;DKFZp666N164;FOV", + "SDK2", + "GCS1", + "HSPA1A;HEL-S-103;HSPA1B", + "DKFZp781M0386", + "IGL@", + "DKFZp686O1553", + "ITLN1;ITLN2", + "MIA3", + "WDR44;DKFZp761M142", + "COLEC12", + "V1-13", + "V5-6;VLC8;IGLV4-69", + "APOM", + "NANS;HEL-S-100", + "ATF6B", + "IGL@", + "IGH@", + "PM20D1", + "TWF2", + "C2", + "DKFZp686M0562", + "DKFZp686G11190;DKFZp686O01196;DKFZp686H20196", + "DKFZp686M08189", + "DKFZp686P15220", + "DKFZp686I15196", + "CASC4", + "CSPG4", + "SBSN", + "PI16", + "ADAMTSL4", + "SCARA5", + "QSOX2", + "DKFZp686K18196", + "HIST2H3A", + "ADAMTS13", + "NEGR1", + "MEGF8", + "B3GNT8", + "GPR126", + "SERPINA11", + "OAF", + "FERMT3", + "PKHD1L1", + "LSR", + "TREML1", + "SERPINA12", + "FAM20C", + "TMEM132C", + "IGL@", + "PCSK9", + "PLA2G15", + "HMCN2", + "SNED1", + "OIT3", + "ST8SIA4", + "SMPDL3A", + "FAM3C", + "NEO1", + "MEGF10", + "HMCN1", + "HEL-S-300;PEBP4", + "PARK7;HEL-S-67p", + "OSMR", + "FUCA2", + "COLEC11", + "CHMP4A", + "CDHR2", + "MEGF9", + "ANTXR1;ANTXR1/NNG1 fusion", + "MMRN2", + "ERVMER34-1", + "PARVB", + "SLC38A10", + "PCDH18", + "CD248", + "APMAP", + "MAN1C1", + "MXRA5", + "SEMA3G", + "CBLN4", + "B3GNT2", + "ERAP1;ARTS-1", + "SACS", + "EHD3", + "CNTN3", + "MRC2", + "FETUB;GUGU", + "PCSK1N", + "CD84", + "PLXNA1", + "DBNL", + "TRHDE", + "HEG1", + "NOTCH3", + "NENF", + "PROCR", + "NUDC;NPD011", + "VSIG4", + "PRG3", + "TLN1", + "PLXND1", + "HYOU1", + "APOB" + ], + "legendgroup": "non_sig", + "marker": { + "color": "#b2b2b2", + "symbol": "circle" + }, + "mode": "markers", + "name": "non_sig", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 0.0015178102061490506, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + -0.0006550417318536006, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 0.0006133271387689376, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "xaxis": "x", + "y": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 0.003923885696906857, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 0.003133786540256547, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 0.001354570081165944, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "yaxis": "y" + }, + { + "hovertemplate": "%{hovertext}

1% FDR=sig
log2 fold change=%{x}
-log10(p-value)=%{y}", + "hovertext": [ + "VCL;HEL114", + "C9", + "APOC1", + "APOL1", + "CLEC3B", + "APOA1", + "SERPINA10", + "SERPINA1", + "SERPINA4", + "SERPINA5", + "SERPINA3", + "SERPINC1", + "C1QC", + "HSPG2", + "C1QB", + "ANPEP", + "SPARCL1", + "LCP1;HEL-S-37", + "IGKV2D-28", + "FCGBP", + "IGHM", + "GPX3", + "C1S", + "SAA2-SAA4;SAA4", + "F5", + "VH6DJ;IGHV6-1", + "IGHV3-74", + "CRTAC1", + "IGHV5-51", + "CST3", + "APOE", + "CETP", + "LGALS3BP", + "PROS1", + "TGFBI", + "PRG4", + "IGHV1-24", + "TNXB", + "ECM1", + "AZGP1", + "SERPINF1", + "SEPP1", + "IGLC7", + "IGKV A18", + "ITIH2", + "APOC3", + "CP", + "TTR;HEL111", + "CFD;DF", + "IGHG1", + "CNDP1", + "C7", + "IGFALS", + "PROZ", + "AGT", + "CFHR1", + "CD14", + "PZP", + "PLTP", + "KNG1", + "C1R", + "ATRN", + "KNG1", + "C4BPA", + "CFB", + "PLXDC2", + "C8B", + "AHSG", + "ITIH4", + "AMY1A;AMY1B", + "APOB", + "IGJ;JCHAIN", + "APOD", + "ALB", + "HBA1;HBA2", + "BCHE", + "APOH", + "HBB", + "COL6A3;DKFZp686K04147", + "VTN", + "CFI", + "SERPINA1", + "SERPING1", + "F9;F9 p22;factor IX F9", + "KLKB1", + "KRT1", + "SHBG", + "APOC4-APOC2;APOC2", + "QSOX1;BPGF-1", + "FCN3;UNQ172", + "APOM", + "F13A1", + "F2", + "HP", + "HPR", + "F10", + "PLG", + "F12", + "CA1;HEL-S-11", + "A2M", + "C3;HEL-S-62p", + "C5", + "IGHG4", + "FGA", + "FGB;HEL-S-78p", + "FGG", + "APCS;HEL-S-92n", + "FN1", + "RBP4", + "AMBP", + "ORM1;HEL-S-153w", + "HPX", + "F11", + "CAT", + "HRG", + "HEL-S-163pA;A1BG", + "VWF", + "F13B", + "SERPINA7", + "SERPIND1", + "GSN", + "APOA4", + "CKM", + "C8A", + "C8G", + "SERPINA6", + "CFH", + "SERPINF2", + "DBH", + "C4A", + "C4B", + "IGHD", + "CLU", + "HSPA5;HEL-S-89n", + "C6", + "HSP90B1;TRA1;HEL-S-125m", + "CPN1", + "DSP;DSP variant protein", + "LBP", + "VCAM1", + "ORM2", + "ITIH1", + "FLNA;FLJ00119", + "CPN2", + "FBLN1", + "PON1", + "CDH5", + "KRT9", + "BTD", + "AFM", + "MASP1", + "LUM", + "ACTB;PS1TP5BP1;ACTG1", + "GPLD1", + "ITIH3", + "LRP1", + "IGKC", + "HABP2", + "V2-17", + "scFv", + "HMFT1766", + "VASN", + "DKFZp686C11235", + "DKFZp686I04196;DKFZp686E23209", + "IGL@", + "IGK@", + "IGK@", + "CD109", + "IGL@", + "FLJ00385", + "CPB2", + "IGHA1;DKFZp686G21220;SNC73;DKFZp686J11235", + "PGLYRP2", + "C1RL", + "PCYOX1", + "APOA2", + "HEL-214" + ], + "legendgroup": "sig", + "marker": { + "color": "#6666ff", + "symbol": "circle" + }, + "mode": "markers", + "name": "sig", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": [ + -0.7179378062093456, + 0.34673608014156443, + 0.41944035001348823, + -0.10754120169465864, + -0.06925841702872759, + 0.039454019656389505, + -0.011030241613497083, + 0.08367127784077866, + -0.07179042162196225, + 0.28791514334321633, + 0.1452492250552737, + 0.251611764891706, + -0.3459294397954338, + 0.1522696281374074, + -0.4507680766031328, + -0.6227244006881989, + -0.19470186099394837, + -0.08247059688131131, + -0.4733377615553387, + -0.8259077594509527, + -0.4183990526862331, + 0.06323686118514615, + 0.0419836152980082, + -0.3961780635903125, + 0.02367318013157771, + -0.6006315335812218, + -0.41237372059999444, + -0.15095046425114944, + -0.5728126370041586, + 0.07338358755325558, + -0.09749951082370245, + -0.024866536296876518, + -1.0274121733069883, + -0.034664627856709984, + -0.3916821441650278, + -0.17885753830609374, + -0.6204032317394024, + -0.3705403862253611, + -0.10445243581625618, + 0.211042607016676, + -0.22563438051604123, + -0.07059589344241601, + -0.5304011460416298, + -0.2556266199805073, + 0.1612820584336987, + 0.15253374124819885, + 0.1738882255857277, + -0.03364046267393661, + 0.03496116236918567, + -0.18895037959037708, + 0.30957706636337434, + -0.5490845321533904, + 0.2155396755191923, + -0.7152510566866965, + -0.12261725782577315, + 0.1608910060202362, + 0.11394777638736642, + 0.45995509409724633, + 0.1118803453798094, + -0.28611151350287756, + 0.0966074874579057, + -0.2257148644588547, + 0.10975863940860364, + -0.07804415609631121, + -0.06486920417546571, + 0.5360286468177975, + 0.028198313770460004, + -0.01928132880296829, + 0.2741896189220938, + -0.6032934225666295, + 0.4084071235539568, + -0.24391558710607342, + 0.20313435045708772, + 0.008358402019638334, + -0.13471513962041826, + 0.08064182577583523, + 0.14831190596726174, + -0.15021070638570677, + 0.3185974814238044, + -0.044705611779555454, + -0.0895399765622038, + -0.3239556958789862, + 0.09386972513938474, + -0.11222199027026036, + -0.11372371607729193, + 0.4020752463002317, + 0.5115977358981922, + 0.4318658952367116, + -0.24754994928030882, + -0.4787002042485078, + 0.4213868159449241, + 0.1825563918938613, + 0.17215135856238817, + 0.3414594260442385, + 0.3828101404815598, + -0.2364112797806257, + 0.12666212165714796, + -0.13492377378429765, + -0.4116573515952595, + -0.11689596609328134, + -0.15731020326094125, + 0.01820225112543028, + -0.546095865509777, + 0.19685921162544417, + 0.18705988984197575, + 0.26817715310608037, + -0.02575683402074347, + -0.25312784406214917, + -0.10923249202894425, + 0.5868882911665381, + 0.15577407279088362, + -0.02040292650290354, + 0.11915216654070093, + -0.5943861229624225, + 0.018288078072096425, + 0.061653150166065984, + -0.9250971268791801, + 0.05133473363546415, + -0.1310551007118015, + -0.004155769244185592, + 0.12065216459166805, + 0.3589450146624529, + -0.01615814839612284, + -0.13893194290370303, + -0.16752137366504627, + 0.06149570229133161, + -0.16194459761447888, + 0.3072063583167761, + 0.1646872581207539, + -0.20965360788562393, + -0.17120665406703495, + -0.1369829019774187, + 0.10539348359264977, + -0.1150328788620989, + 0.12884515606043934, + -0.0998229511700579, + 0.0659032184294226, + -0.1779563101499626, + -0.18297542979494708, + -0.4987743764257395, + -0.20599642695590603, + 0.1814413530138026, + 0.38255598836530424, + 0.08564707368047664, + -0.21739309084430758, + 0.13852837486744107, + -0.34923925340382667, + -0.5039780547265487, + -0.14512891769383884, + -0.459937462227451, + -0.11859548510701501, + -0.1289276497987153, + 1.0296738744046827, + 0.2847463236107117, + 0.3800870440228685, + 0.09802542427440741, + 0.5392315351639283, + -0.15819919245513248, + -0.48558773928479937, + -0.3226830187920626, + 0.32328255199354317, + -0.4929538191678269, + -0.2517364207528203, + -0.027802440198279044, + -0.2764930395535501, + -0.11925236840607667, + -0.014075733979154847, + -0.060948999072437005, + -0.2071329087167868, + -0.3280464413334805, + 0.24134412373066283, + 0.3583538619210813, + 0.06791981299793548, + 0.263564907078667, + 0.27958140531276143, + -0.0756305598830167, + -0.1604187809506783 + ], + "xaxis": "x", + "y": [ + 0.9689101053448507, + 1.2709732130034408, + 1.7871758110505658, + 0.24815187119570847, + 0.15227959035322414, + 0.12729826328689473, + 0.018875653009612574, + 0.7345512227330486, + 0.26192418847044385, + 0.25741285662897045, + 0.4495583042006329, + 2.899604218823895, + 1.394988780963667, + 0.268176627096163, + 1.3851696526466513, + 1.3657267430773066, + 0.12020976390977807, + 0.14307685560575506, + 0.8357954404087552, + 1.9799490580042427, + 0.9464381483567925, + 0.12259769709250694, + 0.19007143714635902, + 0.9797650184747713, + 0.07039577279852396, + 0.8735488100164758, + 1.1089806126804664, + 0.24255006968425408, + 1.668371845478722, + 0.09835575651860384, + 0.2754785179287966, + 0.02481135551711831, + 4.112665178640874, + 0.16183080116953863, + 2.1438027647300086, + 0.28383928377938394, + 0.9662432986662113, + 0.7592314448766139, + 0.3023645531752248, + 1.0535791145836888, + 1.1211677704889513, + 0.14714560647302133, + 0.28006500035388704, + 0.21090370002896233, + 1.1579455231134772, + 0.3986717409107289, + 0.8342749254774697, + 0.08461285733211153, + 0.06078219443189871, + 0.3176080447094795, + 0.5529912544404543, + 1.1376556851754094, + 0.35079583228780065, + 0.986698926999476, + 0.6146884203538138, + 0.33095498415623803, + 0.17207362273199062, + 0.26679463761899425, + 0.3384507926711643, + 0.3502545565012387, + 0.5721830189312839, + 1.3307492971253412, + 0.46939325389009595, + 0.22638038069646704, + 0.3138435298997552, + 1.1734957535532715, + 0.09633043344858451, + 0.06138212488897322, + 1.780520263398458, + 0.7451601528483485, + 1.2766460616110158, + 0.4246443983567706, + 0.5248160756515595, + 0.044140785040026755, + 0.3014068025986023, + 0.22186682515467435, + 0.4068134005487726, + 0.3895218145000253, + 0.2163249388151191, + 0.16845464461770257, + 0.35833620660239157, + 0.7385139143871734, + 0.3895452977544467, + 0.3626478216447963, + 0.5858990829356313, + 0.7448460657419579, + 0.7214612908977475, + 0.9355203422939747, + 0.45700725836243533, + 1.0032611318911913, + 3.049799605738295, + 0.3344501663116267, + 1.084290775387458, + 0.39089781682424235, + 0.6763285882996225, + 1.1314643013847252, + 0.6541954507994642, + 0.22158726508280402, + 1.155791462616193, + 0.19062774107768804, + 1.4465290785688563, + 0.08119982870113691, + 0.3353629211275707, + 1.6169984788924343, + 0.9015080276380966, + 1.586292047879841, + 0.07983709487663322, + 0.961738203595774, + 0.16438286256159532, + 2.270335347774253, + 0.3610551331665246, + 0.1131926384329986, + 0.38276575765210186, + 1.8398916327348915, + 0.038219584434234455, + 0.38404872326070666, + 1.3242303870661396, + 0.09567662340958083, + 0.5323333276131118, + 0.007875928063051648, + 0.7139799431145988, + 1.0711840503440322, + 0.01305349007651525, + 0.43025275727546497, + 0.3832963587481722, + 0.1982119554105198, + 1.233831238538906, + 1.34912727402651, + 0.11743177174060959, + 0.19648419238219295, + 0.6277877245342225, + 0.11490156013255944, + 0.7278775866893241, + 0.16676137033141927, + 1.0601668906942998, + 0.23941653999688395, + 0.1653440331281238, + 0.21355336730500304, + 0.2410105302432411, + 0.5498555025540022, + 0.6964406078735816, + 1.1384339635839655, + 0.41535974035795864, + 0.20941846080100462, + 0.6367478993631742, + 0.19363139505396537, + 1.0802055239982973, + 0.49835271973978584, + 0.1973012310347237, + 2.3837571990289668, + 0.34761219771428253, + 0.5268579805878524, + 2.4119839733753863, + 2.2280561174671467, + 0.6994315629304624, + 0.06384979679216247, + 1.1115505350495893, + 0.5505826369507191, + 1.056830260252383, + 0.5318428393294974, + 1.356505879134698, + 1.1718335429038997, + 0.4549361826272863, + 0.05153073777918955, + 0.4982987242165866, + 0.320031750427214, + 0.04460250565936242, + 0.058386314048128274, + 0.8061119322410575, + 0.39981005692711535, + 1.5739698663098431, + 0.7323737923301341, + 0.3216943959795577, + 0.8372340489823369, + 0.5002940752130047, + 0.2746524649724523, + 1.323217247888996 + ], + "yaxis": "y" + } + ], + "layout": { + "height": 700, + "legend": { + "title": { + "text": "1% FDR" + }, + "tracegroupgap": 0 + }, + "margin": { + "t": 60 + }, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "rgb(36,36,36)" + }, + "error_y": { + "color": "rgb(36,36,36)" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "rgb(36,36,36)", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "rgb(36,36,36)" + }, + "baxis": { + "endlinecolor": "rgb(36,36,36)", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "rgb(36,36,36)" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.6 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + }, + "colorscale": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "rgb(237,237,237)" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "rgb(217,217,217)" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 1, + "tickcolor": "rgb(36,36,36)", + "ticks": "outside" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "rgb(103,0,31)" + ], + [ + 0.1, + "rgb(178,24,43)" + ], + [ + 0.2, + "rgb(214,96,77)" + ], + [ + 0.3, + "rgb(244,165,130)" + ], + [ + 0.4, + "rgb(253,219,199)" + ], + [ + 0.5, + "rgb(247,247,247)" + ], + [ + 0.6, + "rgb(209,229,240)" + ], + [ + 0.7, + "rgb(146,197,222)" + ], + [ + 0.8, + "rgb(67,147,195)" + ], + [ + 0.9, + "rgb(33,102,172)" + ], + [ + 1, + "rgb(5,48,97)" + ] + ], + "sequential": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ], + "sequentialminus": [ + [ + 0, + "#440154" + ], + [ + 0.1111111111111111, + "#482878" + ], + [ + 0.2222222222222222, + "#3e4989" + ], + [ + 0.3333333333333333, + "#31688e" + ], + [ + 0.4444444444444444, + "#26828e" + ], + [ + 0.5555555555555556, + "#1f9e89" + ], + [ + 0.6666666666666666, + "#35b779" + ], + [ + 0.7777777777777778, + "#6ece58" + ], + [ + 0.8888888888888888, + "#b5de2b" + ], + [ + 1, + "#fde725" + ] + ] + }, + "colorway": [ + "#1F77B4", + "#FF7F0E", + "#2CA02C", + "#D62728", + "#9467BD", + "#8C564B", + "#E377C2", + "#7F7F7F", + "#BCBD22", + "#17BECF" + ], + "font": { + "color": "rgb(36,36,36)" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "rgb(232,232,232)", + "gridwidth": 2, + "linecolor": "rgb(36,36,36)", + "showbackground": true, + "showgrid": false, + "showline": true, + "ticks": "outside", + "zeroline": false, + "zerolinecolor": "rgb(36,36,36)" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "rgb(232,232,232)", + "gridwidth": 2, + "linecolor": "rgb(36,36,36)", + "showbackground": true, + "showgrid": false, + "showline": true, + "ticks": "outside", + "zeroline": false, + "zerolinecolor": "rgb(36,36,36)" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "rgb(232,232,232)", + "gridwidth": 2, + "linecolor": "rgb(36,36,36)", + "showbackground": true, + "showgrid": false, + "showline": true, + "ticks": "outside", + "zeroline": false, + "zerolinecolor": "rgb(36,36,36)" + } + }, + "shapedefaults": { + "fillcolor": "black", + "line": { + "width": 0 + }, + "opacity": 0.3 + }, + "ternary": { + "aaxis": { + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside" + }, + "baxis": { + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside", + "title": { + "standoff": 15 + }, + "zeroline": false, + "zerolinecolor": "rgb(36,36,36)" + }, + "yaxis": { + "automargin": true, + "gridcolor": "rgb(232,232,232)", + "linecolor": "rgb(36,36,36)", + "showgrid": false, + "showline": true, + "ticks": "outside", + "title": { + "standoff": 15 + }, + "zeroline": false, + "zerolinecolor": "rgb(36,36,36)" + } + } + }, + "width": 600, + "xaxis": { + "anchor": "y", + "domain": [ + 0, + 1 + ], + "title": { + "text": "log2 fold change" + } + }, + "yaxis": { + "anchor": "x", + "domain": [ + 0, + 1 + ], + "title": { + "text": "-log10(p-value)" + } + } + } + }, + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "transposed = dataset.mat.transpose()\n", + "\n", + "\n", + " # needs to be lpog2 transformed for fold change calculations\n", + "transposed = transposed.transform(lambda x: np.log2(x))\n", + "\n", + "transposed[dataset.index_column] = transposed.index\n", + "transposed = transposed.reset_index(drop=True)\n", + "\n", + "ValueError: Transform function failed\n", + "res_ttest, tlim_ttest = functions.perform_ttest_analysis(\n", + " transposed,\n", + " c1 =list(dataset.metadata[dataset.metadata[\"disease\"]==\"type 2 diabetes mellitus\"][\"sample\"]), \n", + " c2=list(dataset.metadata[dataset.metadata[\"disease\"]==\"type 2 diabetes mellitus|non-alcoholic fatty liver disease\"][\"sample\"]),\n", + " s0=0.05, \n", + " n_perm=10,\n", + " fdr=0.01,\n", + " id_col=dataset.index_column,\n", + " parallelize=True\n", + " )\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "f9222925", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.017941516477081355" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tlim_ttest\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "156a9ded", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
1_31_C61_32_C71_33_C81_34_C91_35_C101_36_C111_37_C121_38_D11_39_D21_40_D3...1_70_F91_71_F101_72_F111_73_F121_74_G11_75_G21_76_G31_77_G41_78_G5Gene names
0-inf-inf-inf-inf-inf-inf-inf21.147868-inf-inf...-inf-inf-inf-inf-inf-inf-inf-inf-infSERPINE1
1-inf-inf-inf-inf-inf23.523368-inf-inf-inf-inf...-inf-inf-inf-inf-inf-inf-inf-inf-infMYH11
227.12198628.56550828.15330127.10289625.79555728.07663527.73866627.51690728.41163227.460374...25.53599625.85863527.28392126.81885025.77298827.53860327.05734426.78394225.764788VCL;HEL114
3-inf-inf-inf22.322951-inf-inf-inf-inf-inf-inf...-inf-inf-inf-inf-inf-inf-inf-inf-infPSAP
431.90551731.30720532.45024632.39973432.04433432.25898132.07469731.69000032.19759432.307097...31.67282531.19788732.22707932.20253531.74149732.17631931.44771231.53059832.132191C9
..................................................................
89423.013845-inf-inf-inf-inf23.038034-inf-inf-inf-inf...-inf-inf-inf-inf-inf-inf-inf-inf-infPLXND1
89527.272576-inf26.15665124.90251426.796621-inf-inf-inf27.851326-inf...-inf-inf-inf22.079852-inf-inf-inf26.896891-infHYOU1
896-inf-inf-inf-inf-inf-inf-inf-inf-inf-inf...-inf-inf-inf-inf-inf-inf-inf-inf-infAPOB
89733.92193834.21798234.07996634.16862934.46221933.92556834.07821734.10094634.24296234.303481...34.37910434.37321633.97843734.24763833.95350334.27766734.06695734.20965533.585421APOA2
89836.54466736.20490936.12953436.28869136.75806736.68342636.57274536.69072936.72364736.229810...36.25892836.51612036.75620436.67253536.38281236.46293536.89859236.47078836.186044HEL-214
\n", + "

899 rows × 49 columns

\n", + "
" + ], + "text/plain": [ + " 1_31_C6 1_32_C7 1_33_C8 1_34_C9 1_35_C10 1_36_C11 \\\n", + "0 -inf -inf -inf -inf -inf -inf \n", + "1 -inf -inf -inf -inf -inf 23.523368 \n", + "2 27.121986 28.565508 28.153301 27.102896 25.795557 28.076635 \n", + "3 -inf -inf -inf 22.322951 -inf -inf \n", + "4 31.905517 31.307205 32.450246 32.399734 32.044334 32.258981 \n", + ".. ... ... ... ... ... ... \n", + "894 23.013845 -inf -inf -inf -inf 23.038034 \n", + "895 27.272576 -inf 26.156651 24.902514 26.796621 -inf \n", + "896 -inf -inf -inf -inf -inf -inf \n", + "897 33.921938 34.217982 34.079966 34.168629 34.462219 33.925568 \n", + "898 36.544667 36.204909 36.129534 36.288691 36.758067 36.683426 \n", + "\n", + " 1_37_C12 1_38_D1 1_39_D2 1_40_D3 ... 1_70_F9 1_71_F10 \\\n", + "0 -inf 21.147868 -inf -inf ... -inf -inf \n", + "1 -inf -inf -inf -inf ... -inf -inf \n", + "2 27.738666 27.516907 28.411632 27.460374 ... 25.535996 25.858635 \n", + "3 -inf -inf -inf -inf ... -inf -inf \n", + "4 32.074697 31.690000 32.197594 32.307097 ... 31.672825 31.197887 \n", + ".. ... ... ... ... ... ... ... \n", + "894 -inf -inf -inf -inf ... -inf -inf \n", + "895 -inf -inf 27.851326 -inf ... -inf -inf \n", + "896 -inf -inf -inf -inf ... -inf -inf \n", + "897 34.078217 34.100946 34.242962 34.303481 ... 34.379104 34.373216 \n", + "898 36.572745 36.690729 36.723647 36.229810 ... 36.258928 36.516120 \n", + "\n", + " 1_72_F11 1_73_F12 1_74_G1 1_75_G2 1_76_G3 1_77_G4 \\\n", + "0 -inf -inf -inf -inf -inf -inf \n", + "1 -inf -inf -inf -inf -inf -inf \n", + "2 27.283921 26.818850 25.772988 27.538603 27.057344 26.783942 \n", + "3 -inf -inf -inf -inf -inf -inf \n", + "4 32.227079 32.202535 31.741497 32.176319 31.447712 31.530598 \n", + ".. ... ... ... ... ... ... \n", + "894 -inf -inf -inf -inf -inf -inf \n", + "895 -inf 22.079852 -inf -inf -inf 26.896891 \n", + "896 -inf -inf -inf -inf -inf -inf \n", + "897 33.978437 34.247638 33.953503 34.277667 34.066957 34.209655 \n", + "898 36.756204 36.672535 36.382812 36.462935 36.898592 36.470788 \n", + "\n", + " 1_78_G5 Gene names \n", + "0 -inf SERPINE1 \n", + "1 -inf MYH11 \n", + "2 25.764788 VCL;HEL114 \n", + "3 -inf PSAP \n", + "4 32.132191 C9 \n", + ".. ... ... \n", + "894 -inf PLXND1 \n", + "895 -inf HYOU1 \n", + "896 -inf APOB \n", + "897 33.585421 APOA2 \n", + "898 36.186044 HEL-214 \n", + "\n", + "[899 rows x 49 columns]" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "transposed" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "a57fab3a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Gene namesfctvalpvaltval_s0pval_s0qvalFDRlog2fc-log10(p-value)colorFDR xxx
2VCL;HEL114-0.717938-1.7055750.107421-1.5244910.1469070.0sig-0.7179380.968910downsig
4C90.3467362.0836780.0535831.6022500.1286560.0sig0.3467361.270973upsig
7APOC10.4194402.6831960.0163242.0329480.0589950.0sig0.4194401.787176upsig
13APOL1-0.107541-0.5880010.564739-0.4617630.6504680.0sig-0.1075410.248152downsig
29CLEC3B-0.069258-0.3864700.704240-0.3021650.7664190.0sig-0.0692580.152280downsig
.......................................
850PGLYRP20.0679200.7286160.4767660.4742420.6417350.0sig0.0679200.321694upsig
876C1RL0.2635651.5303200.1454671.1860080.2529330.0sig0.2635650.837234upsig
881PCYOX10.2795811.0351020.3160140.8734180.3953550.0sig0.2795810.500294upsig
897APOA2-0.075631-0.6398760.531309-0.4496580.6589890.0sig-0.0756310.274652downsig
898HEL-214-0.160419-2.1465150.047510-1.2860820.2167150.0sig-0.1604191.323217downsig
\n", + "

180 rows × 12 columns

\n", + "
" + ], + "text/plain": [ + " Gene names fc tval pval tval_s0 pval_s0 qval FDR \\\n", + "2 VCL;HEL114 -0.717938 -1.705575 0.107421 -1.524491 0.146907 0.0 sig \n", + "4 C9 0.346736 2.083678 0.053583 1.602250 0.128656 0.0 sig \n", + "7 APOC1 0.419440 2.683196 0.016324 2.032948 0.058995 0.0 sig \n", + "13 APOL1 -0.107541 -0.588001 0.564739 -0.461763 0.650468 0.0 sig \n", + "29 CLEC3B -0.069258 -0.386470 0.704240 -0.302165 0.766419 0.0 sig \n", + ".. ... ... ... ... ... ... ... ... \n", + "850 PGLYRP2 0.067920 0.728616 0.476766 0.474242 0.641735 0.0 sig \n", + "876 C1RL 0.263565 1.530320 0.145467 1.186008 0.252933 0.0 sig \n", + "881 PCYOX1 0.279581 1.035102 0.316014 0.873418 0.395355 0.0 sig \n", + "897 APOA2 -0.075631 -0.639876 0.531309 -0.449658 0.658989 0.0 sig \n", + "898 HEL-214 -0.160419 -2.146515 0.047510 -1.286082 0.216715 0.0 sig \n", + "\n", + " log2fc -log10(p-value) color FDR xxx \n", + "2 -0.717938 0.968910 down sig \n", + "4 0.346736 1.270973 up sig \n", + "7 0.419440 1.787176 up sig \n", + "13 -0.107541 0.248152 down sig \n", + "29 -0.069258 0.152280 down sig \n", + ".. ... ... ... ... \n", + "850 0.067920 0.321694 up sig \n", + "876 0.263565 0.837234 up sig \n", + "881 0.279581 0.500294 up sig \n", + "897 -0.075631 0.274652 down sig \n", + "898 -0.160419 1.323217 down sig \n", + "\n", + "[180 rows x 12 columns]" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "plot.plotting_data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73b454d4", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "27ae2977", + "metadata": {}, + "outputs": [], + "source": [ + "plot.plotting_data['FDR xxx '] = [\"sig\" if abs(x) >= 0.017 else \"non_sig\" for x in plot.plotting_data['tval_s0']]" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "d16ee17f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "abs(-1)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/alphastats/DataSet.py b/alphastats/DataSet.py index 17689f54..b475271f 100644 --- a/alphastats/DataSet.py +++ b/alphastats/DataSet.py @@ -75,7 +75,14 @@ def _check_loader(self, loader): loader : loader """ if not isinstance( - loader, (AlphaPeptLoader, MaxQuantLoader, DIANNLoader, FragPipeLoader, SpectronautLoader) + loader, + ( + AlphaPeptLoader, + MaxQuantLoader, + DIANNLoader, + FragPipeLoader, + SpectronautLoader, + ), ): raise LoaderError( "loader must be from class: AlphaPeptLoader, MaxQuantLoader, DIANNLoader, FragPipeLoader or SpectronautLoader" @@ -115,7 +122,7 @@ def create_matrix(self): """ regex_find_intensity_columns = self.intensity_column.replace("[sample]", ".*") - + df = self.rawinput df = df.set_index(self.index_column) df = df.filter(regex=(regex_find_intensity_columns), axis=1) diff --git a/alphastats/cli.py b/alphastats/cli.py index 33b2367a..097cf7c0 100644 --- a/alphastats/cli.py +++ b/alphastats/cli.py @@ -1,5 +1,7 @@ -import alphastats +import alphastats + def run(): - import alphastats + import alphastats + alphastats.gui.gui.run() diff --git a/alphastats/gui/AlphaPeptStats.py b/alphastats/gui/AlphaPeptStats.py index b9de13b9..3b7f8bba 100644 --- a/alphastats/gui/AlphaPeptStats.py +++ b/alphastats/gui/AlphaPeptStats.py @@ -1,4 +1,5 @@ import streamlit as st + st.set_page_config(layout="wide") try: @@ -6,7 +7,8 @@ except ModuleNotFoundError: from utils.ui_helper import sidebar_info, img_to_bytes import os -#from PIL import Image + +# from PIL import Image # centering with streamlit is not really centered @@ -42,8 +44,7 @@ ) st.markdown( - header_html, - unsafe_allow_html=True, + header_html, unsafe_allow_html=True, ) ## diff --git a/alphastats/gui/__init__.py b/alphastats/gui/__init__.py index 7a69b75e..dcaea0ee 100644 --- a/alphastats/gui/__init__.py +++ b/alphastats/gui/__init__.py @@ -1 +1 @@ -from .gui import run \ No newline at end of file +from .gui import run diff --git a/alphastats/gui/pages/02_Import Data.py b/alphastats/gui/pages/02_Import Data.py index 881734e9..92560007 100644 --- a/alphastats/gui/pages/02_Import Data.py +++ b/alphastats/gui/pages/02_Import Data.py @@ -18,7 +18,6 @@ from alphastats import DataSet - import pandas as pd import plotly.express as px @@ -174,16 +173,30 @@ def upload_softwarefile(software): st.session_state["loader"] = loader +def create_metadata_file(): + dataset = DataSet(loader=st.session_state.loader) + st.session_state["metadata_columns"] = ["sample"] + metadata = dataset.metadata + + if st.button("Add Column"): + st.write("xxx") + column_name = st.text_input("Column name", "") + metadata[column_name] = None + + metadata = st.experimental_data_editor(metadata, num_rows="fixed") + + # st.session_state.loader + + def upload_metadatafile(software): st.write("\n\n") - st.markdown("### 3. Upload corresponding metadata.") - st.file_uploader( - "Upload metadata file. with information about your samples", - key="metadatafile", + st.markdown("### 3. Prepare Metadata.") + metadatafile_upload = st.file_uploader( + "Upload metadata file. with information about your samples", key="metadatafile", ) - if st.session_state.metadatafile is not None: + if metadatafile_upload is not None: metadatafile_df = read_uploaded_file_into_df(st.session_state.metadatafile) # display metadata @@ -207,6 +220,9 @@ def upload_metadatafile(software): display_loaded_dataset() + if st.button("Create metadata file"): + create_metadata_file() + if st.button("Create a DataSet without metadata"): st.session_state["dataset"] = DataSet(loader=st.session_state.loader) st.session_state["metadata_columns"] = ["sample"] @@ -219,14 +235,16 @@ def upload_metadatafile(software): def load_sample_data(): _this_file = os.path.abspath(__file__) _this_directory = os.path.dirname(_this_file) - filepath = os.path.join(_this_directory, "sample_data/proteinGroups.txt").replace("pages/","") - metadatapath = os.path.join(_this_directory, "sample_data/metadata.xlsx").replace("pages/","") - - loader = MaxQuantLoader(file=filepath) - ds = DataSet( - loader=loader, metadata_path=metadatapath, sample_column="sample" + filepath = os.path.join(_this_directory, "sample_data/proteinGroups.txt").replace( + "pages/", "" + ) + metadatapath = os.path.join(_this_directory, "sample_data/metadata.xlsx").replace( + "pages/", "" ) - + + loader = MaxQuantLoader(file=filepath) + ds = DataSet(loader=loader, metadata_path=metadatapath, sample_column="sample") + ds.metadata = ds.metadata[ [ "sample", @@ -247,7 +265,14 @@ def import_data(): software = st.selectbox( "Select your Proteomics Software", - options=["", + "MaxQuant", + "AlphaPept", + "DIANN", + "Fragpipe", + "Spectronaut", + ], ) session_state_empty = False @@ -304,9 +329,11 @@ def empty_session_state(): from streamlit.runtime import get_instance from streamlit.runtime.scriptrunner.script_run_context import get_script_run_ctx + user_session_id = get_script_run_ctx().session_id st.session_state["user_session_id"] = user_session_id + sidebar_info() diff --git a/alphastats/gui/pages/03_Data Overview.py b/alphastats/gui/pages/03_Data Overview.py index dcbcccf3..88fa3c42 100644 --- a/alphastats/gui/pages/03_Data Overview.py +++ b/alphastats/gui/pages/03_Data Overview.py @@ -4,12 +4,12 @@ @st.cache_data -def convert_df(df, user_session_id = st.session_state.user_session_id): +def convert_df(df, user_session_id=st.session_state.user_session_id): return df.to_csv().encode("utf-8") @st.cache_data -def get_display_matrix(user_session_id = st.session_state.user_session_id): +def get_display_matrix(user_session_id=st.session_state.user_session_id): processed_df = pd.DataFrame( st.session_state.dataset.mat.values, @@ -45,20 +45,22 @@ def display_matrix(): st.markdown("## DataSet overview") c1, c2 = st.columns(2) - + with c1: st.markdown("**Intensity distribution raw data per sample**") st.plotly_chart( st.session_state.distribution_plot.update_layout(plot_bgcolor="white"), - use_container_width=True + use_container_width=True, ) - + with c2: st.markdown("**Intensity distribution data per sample used for analysis**") fig_processed = st.session_state.dataset.plot_sampledistribution() - st.plotly_chart(fig_processed.update_layout(plot_bgcolor="white"), use_container_width=True) + st.plotly_chart( + fig_processed.update_layout(plot_bgcolor="white"), use_container_width=True + ) display_matrix() diff --git a/alphastats/gui/pages/03_Preprocessing.py b/alphastats/gui/pages/03_Preprocessing.py index bf4fc045..80a07e51 100644 --- a/alphastats/gui/pages/03_Preprocessing.py +++ b/alphastats/gui/pages/03_Preprocessing.py @@ -12,7 +12,7 @@ def preprocessing(): st.markdown( "Before analyzing your data, consider normalizing and imputing your data as well as the removal of contaminants. " - + "A more detailed description about the preprocessing methods can be found in the AlphaPeptStats" + + "A more detailed description about the preprocessing methods can be found in the AlphaPeptStats" + "[documentation](https://alphapeptstats.readthedocs.io/en/main/data_preprocessing.html)." ) @@ -30,8 +30,7 @@ def preprocessing(): ) log2_transform = st.selectbox( - "Log2-transform dataset", - options=[True, False], + "Log2-transform dataset", options=[True, False], ) normalization = st.selectbox( @@ -61,25 +60,29 @@ def preprocessing(): pd.DataFrame.from_dict(preprocessing, orient="index").astype(str), use_container_width=True, ) - + with c2: st.markdown("**Intensity Distribution per sample**") fig_none_processed = st.session_state.dataset.plot_sampledistribution() - st.plotly_chart(fig_none_processed.update_layout(plot_bgcolor="white"), use_container_width=True) - + st.plotly_chart( + fig_none_processed.update_layout(plot_bgcolor="white"), + use_container_width=True, + ) + if submitted: st.markdown("**Intensity Distribution after preprocessing per sample**") fig_processed = st.session_state.dataset.plot_sampledistribution() - st.plotly_chart(fig_processed.update_layout(plot_bgcolor="white"), use_container_width=True) - + st.plotly_chart( + fig_processed.update_layout(plot_bgcolor="white"), + use_container_width=True, + ) + reset_steps = st.button("Reset all Preprocessing steps") - + if reset_steps: reset_preprocessing() - - def reset_preprocessing(): st.session_state.dataset.create_matrix() preprocessing = st.session_state.dataset.preprocessing_info @@ -97,8 +100,7 @@ def main_preprocessing(): if "dataset" in st.session_state: preprocessing() - - + else: st.info("Import Data first") diff --git a/alphastats/gui/pages/04_Analysis.py b/alphastats/gui/pages/04_Analysis.py index b1f6757d..a2a2e81b 100644 --- a/alphastats/gui/pages/04_Analysis.py +++ b/alphastats/gui/pages/04_Analysis.py @@ -6,15 +6,12 @@ try: from alphastats.gui.utils.ui_helper import sidebar_info - from alphastats.gui.utils.analysis_helper import ( - get_analysis, -) + from alphastats.gui.utils.analysis_helper import get_analysis except ModuleNotFoundError: from utils.ui_helper import sidebar_info - from utils.analysis_helper import ( - get_analysis, -) + from utils.analysis_helper import get_analysis + def check_if_options_are_loaded(f): """ @@ -76,7 +73,7 @@ def download_figure(obj, format, plotting_library="plotly"): @st.cache_data -def convert_df(df, user_session_id = st.session_state.user_session_id): +def convert_df(df, user_session_id=st.session_state.user_session_id): return df.to_csv().encode("utf-8") @@ -86,11 +83,7 @@ def download_preprocessing_info(plot): filename = "plot" + plot[0] + "preprocessing_info.csv" csv = convert_df(df) st.download_button( - "Download DataSet Info as .csv", - csv, - filename, - "text/csv", - key="preprocessing", + "Download DataSet Info as .csv", csv, filename, "text/csv", key="preprocessing", ) @@ -134,7 +127,7 @@ def select_analysis(): if "dataset" in st.session_state: - c1, c2 = st.columns((1,2)) + c1, c2 = st.columns((1, 2)) plot_to_display = False df_to_display = False @@ -149,7 +142,7 @@ def select_analysis(): method=method, options_dict=st.session_state.plotting_options ) plot_to_display = True - + elif method in st.session_state.statistic_options.keys(): analysis_result = get_analysis( @@ -161,21 +154,19 @@ def select_analysis(): st.markdown("") st.markdown("") st.markdown("") - with c2: # --- Plot ------------------------------------------------------- if analysis_result is not None and method != "Clustermap" and plot_to_display: - + display_figure(analysis_result) save_plot_to_session_state(analysis_result, method) method_plot = [method, analysis_result] - elif method == "Clustermap": st.write("Download Figure to see full size.") @@ -184,7 +175,6 @@ def select_analysis(): save_plot_to_session_state(analysis_result, method) - # --- STATISTICAL ANALYSIS ------------------------------------------------------- elif analysis_result is not None and df_to_display: @@ -194,8 +184,6 @@ def select_analysis(): filename = method + ".csv" csv = convert_df(analysis_result) - - if analysis_result is not None and method != "Clustermap" and plot_to_display: col1, col2, col3 = st.columns([1, 1, 1]) @@ -208,7 +196,6 @@ def select_analysis(): with col3: download_preprocessing_info(method_plot) - elif analysis_result is not None and df_to_display: col1, col2, col3 = st.columns([1, 1, 1]) @@ -219,14 +206,12 @@ def select_analysis(): download_figure(method_plot, format="svg", plotting_library="seaborn") with col3: - download_preprocessing_info(method_plot) - + download_preprocessing_info(method_plot) + elif analysis_result is not None and df_to_display: st.download_button( - "Download as .csv", csv, filename, "text/csv", key="download-csv" + "Download as .csv", csv, filename, "text/csv", key="download-csv" ) - - else: diff --git a/alphastats/gui/pages/06_Results.py b/alphastats/gui/pages/06_Results.py index c82024c9..415e258c 100644 --- a/alphastats/gui/pages/06_Results.py +++ b/alphastats/gui/pages/06_Results.py @@ -23,7 +23,7 @@ def save_plotly(plot, format): @st.cache_data -def convert_df(df, user_session_id = st.session_state.user_session_id): +def convert_df(df, user_session_id=st.session_state.user_session_id): return df.to_csv().encode("utf-8") diff --git a/alphastats/gui/utils/analysis_helper.py b/alphastats/gui/utils/analysis_helper.py index 2840af8e..a65fc2a1 100644 --- a/alphastats/gui/utils/analysis_helper.py +++ b/alphastats/gui/utils/analysis_helper.py @@ -77,43 +77,41 @@ def gui_volcano_plot_differential_expression_analysis(chosen_parameter_dict): initalize volcano plot object with differential expression analysis results """ volcano_plot = VolcanoPlot( - dataset=st.session_state.dataset, - **chosen_parameter_dict, - plot = False + dataset=st.session_state.dataset, **chosen_parameter_dict, plot=False ) volcano_plot._perform_differential_expression_analysis() volcano_plot._add_hover_data_columns() return volcano_plot + def gui_volcano_plot(): """ Draw Volcano Plot using the VolcanoPlot class """ chosen_parameter_dict = helper_compare_two_groups() method = st.selectbox( - "Differential Analysis using:", - options=["ttest", "anova", "wald", "sam"], + "Differential Analysis using:", options=["ttest", "anova", "wald", "sam"], ) chosen_parameter_dict.update({"method": method}) # TODO streamlit doesnt allow nested columns check for updates - + labels = st.checkbox("Add label") draw_line = st.checkbox("Draw line") alpha = st.number_input( - label="alpha", min_value=0.001, max_value=0.050, value=0.050 - ) + label="alpha", min_value=0.001, max_value=0.050, value=0.050 + ) min_fc = st.select_slider("Foldchange cutoff", range(0, 3), value=1) - + plotting_parameter_dict = { - "labels": labels, - "draw_line": draw_line, - "alpha": alpha, - "min_fc": min_fc, - } + "labels": labels, + "draw_line": draw_line, + "alpha": alpha, + "min_fc": min_fc, + } if method == "sam": perm = st.number_input( @@ -124,11 +122,12 @@ def gui_volcano_plot(): ) chosen_parameter_dict.update({"perm": perm, "fdr": fdr}) - submitted = st.button("Submit") if submitted: - volcano_plot = gui_volcano_plot_differential_expression_analysis(chosen_parameter_dict) + volcano_plot = gui_volcano_plot_differential_expression_analysis( + chosen_parameter_dict + ) volcano_plot._update(plotting_parameter_dict) volcano_plot._annotate_result_df() volcano_plot._plot() @@ -259,15 +258,15 @@ def helper_compare_two_groups(): if group != "< None >": - #col1, col2 = st.columns(2) + # col1, col2 = st.columns(2) unique_values = get_unique_values_from_column(group) - #with col1: + # with col1: group1 = st.selectbox("Group 1", options=unique_values) - #with col2: + # with col2: group2 = st.selectbox("Group 2", options=list(reversed(unique_values))) @@ -282,23 +281,23 @@ def helper_compare_two_groups(): else: - #col1, col2 = st.columns(2) + # col1, col2 = st.columns(2) - #with col1: + # with col1: group1 = st.multiselect( - "Group 1 samples:", - options=st.session_state.dataset.metadata["sample"].to_list(), - ) + "Group 1 samples:", + options=st.session_state.dataset.metadata["sample"].to_list(), + ) - #with col2: + # with col2: group2 = st.multiselect( - "Group 2 samples:", - options=list( - reversed(st.session_state.dataset.metadata["sample"].to_list()) - ), - ) + "Group 2 samples:", + options=list( + reversed(st.session_state.dataset.metadata["sample"].to_list()) + ), + ) intersection_list = list(set(group1).intersection(set(group2))) @@ -350,10 +349,7 @@ def st_tsne_options(method_dict): submitted = st.button("Submit") chosen_parameter_dict.update( - { - "n_iter": n_iter, - "perplexity": perplexity, - } + {"n_iter": n_iter, "perplexity": perplexity,} ) if submitted: diff --git a/alphastats/gui/utils/ui_helper.py b/alphastats/gui/utils/ui_helper.py index 0d196341..21948f08 100644 --- a/alphastats/gui/utils/ui_helper.py +++ b/alphastats/gui/utils/ui_helper.py @@ -34,7 +34,6 @@ def sidebar_info(show_logo=True): ) - def display_sidebar_html_table(): if "dataset" not in st.session_state: diff --git a/alphastats/loader/BaseLoader.py b/alphastats/loader/BaseLoader.py index 836745f6..70cf1981 100644 --- a/alphastats/loader/BaseLoader.py +++ b/alphastats/loader/BaseLoader.py @@ -47,7 +47,7 @@ def _check_if_columns_are_present(self): "FragPipe Format: https://fragpipe.nesvilab.org/docs/tutorial_fragpipe_outputs.html#combined_proteintsv" "MaxQuant Format: http://www.coxdocs.org/doku.php?id=maxquant:table:proteingrouptable" ) - + def _read_all_columns_as_string(self): self.rawinput.columns = self.rawinput.columns.astype(str) diff --git a/alphastats/loader/SpectronautLoader.py b/alphastats/loader/SpectronautLoader.py index 828575aa..c80fe131 100644 --- a/alphastats/loader/SpectronautLoader.py +++ b/alphastats/loader/SpectronautLoader.py @@ -4,7 +4,6 @@ import logging - class SpectronautLoader(BaseLoader): """Loader for Spectronaut outputfiles """ @@ -13,12 +12,12 @@ def __init__( self, file, intensity_column="PG.Quantity", - index_column="PG.ProteinGroups", - sample_column = "R.FileName", + index_column="PG.ProteinGroups", + sample_column="R.FileName", gene_names_column="PG.Genes", - filter_qvalue = True, - qvalue_cutoff = 0.01, - sep="\t" + filter_qvalue=True, + qvalue_cutoff=0.01, + sep="\t", ): """Loads Spectronaut output. Will add contamination column for further analysis. @@ -32,13 +31,13 @@ def __init__( qvalue_cutoff (float, optional): cut off vaéie. Defaults to 0.01. sep (str, optional): file separation of file. Defaults to "\t". """ - + self.software = "Spectronaut" self.intensity_column = intensity_column self.index_column = index_column self.confidence_column = None self.filter_columns = [] - self.evidence_df = None + self.evidence_df = None self.gene_names = None self._read_spectronaut_file(file=file, sep=sep) @@ -46,46 +45,54 @@ def __init__( if filter_qvalue: self._filter_qvalue(qvalue_cutoff=qvalue_cutoff) - self._reshape_spectronaut(sample_column=sample_column, gene_names_column=gene_names_column) + self._reshape_spectronaut( + sample_column=sample_column, gene_names_column=gene_names_column + ) self._add_contamination_column() self._read_all_columns_as_string() - def _reshape_spectronaut(self, sample_column, gene_names_column): """ other proteomics softwares use a wide format (column for each sample) reshape to a wider format """ - self.rawinput["sample"] = self.rawinput[sample_column] + "_" + self.intensity_column - + self.rawinput["sample"] = ( + self.rawinput[sample_column] + "_" + self.intensity_column + ) + indexing_columns = [self.index_column] - + if gene_names_column in self.rawinput.columns.to_list(): self.gene_names = gene_names_column indexing_columns += [self.gene_names] - + keep_columns = [self.intensity_column, "sample"] + indexing_columns - + df = self.rawinput[keep_columns].drop_duplicates() - df = df.pivot(columns='sample', index=indexing_columns, values=self.intensity_column) + df = df.pivot( + columns="sample", index=indexing_columns, values=self.intensity_column + ) df.reset_index(inplace=True) - + self.rawinput = df - + self.intensity_column = "[sample]_" + self.intensity_column def _filter_qvalue(self, qvalue_cutoff): if "EG.Qvalue" not in self.rawinput.columns.to_list(): - raise Warning("Column EG.Qvalue not found in file. File will not be filtered according to q-value.") - + raise Warning( + "Column EG.Qvalue not found in file. File will not be filtered according to q-value." + ) + rows_before_filtering = self.rawinput.shape[0] self.rawinput = self.rawinput[self.rawinput["EG.Qvalue"] < qvalue_cutoff] rows_after_filtering = self.rawinput.shape[0] rows_removed = rows_before_filtering - rows_after_filtering - logging.info(f"{rows_removed} identification with a qvalue below {qvalue_cutoff} have been removed") - - + logging.info( + f"{rows_removed} identification with a qvalue below {qvalue_cutoff} have been removed" + ) + def _read_spectronaut_file(self, file, sep): # some spectronaut files include european decimal separators if isinstance(file, pd.DataFrame): @@ -98,20 +105,18 @@ def _read_spectronaut_file(self, file, sep): df = pd.read_csv(file, sep=sep, decimal=",") self.rawinput = df - - -#filter_with_Qvalue -#TRUE(default) will filter out the intensities that have greater than qvalue_cutoff in EG.Qvalue column. Those intensities will be replaced with zero and will be considered as censored missing values for imputation purpose. -#qvalue_cutoff -#Cutoff for EG.Qvalue. default is 0.01. +# filter_with_Qvalue +# TRUE(default) will filter out the intensities that have greater than qvalue_cutoff in EG.Qvalue column. Those intensities will be replaced with zero and will be considered as censored missing values for imputation purpose. + +# qvalue_cutoff +# Cutoff for EG.Qvalue. default is 0.01. -# Protein Level -# PG.Quantity +#  Protein Level +#  PG.Quantity # PG.ProteinGroups # Peptide Level # F.PeakArea # PEP.StrippedSequence - diff --git a/alphastats/multicova/multicova.py b/alphastats/multicova/multicova.py index 028ebb93..8aa08329 100644 --- a/alphastats/multicova/multicova.py +++ b/alphastats/multicova/multicova.py @@ -23,7 +23,7 @@ def get_std(x): """ Function to calculate the sample standard deviation. """ - std_x = np.sqrt(np.sum((abs(x - x.mean())**2)/(len(x)-1))) + std_x = np.sqrt(np.sum((abs(x - x.mean()) ** 2) / (len(x) - 1))) return std_x @@ -36,18 +36,21 @@ def perform_ttest(x, y, s0): mean_x = np.mean(x) mean_y = np.mean(y) # Get fold-change - fc = mean_x-mean_y + fc = mean_x - mean_y n_x = len(x) n_y = len(y) # pooled standard vatiation # assumes that the two distributions have the same variance - sp = np.sqrt((((n_x-1)*get_std(x)**2) + ((n_y-1)*(get_std(y)**2)))/(n_x+n_y-2)) + sp = np.sqrt( + (((n_x - 1) * get_std(x) ** 2) + ((n_y - 1) * (get_std(y) ** 2))) + / (n_x + n_y - 2) + ) # Get t-values - tval = fc/(sp * (np.sqrt((1/n_x)+(1/n_y)))) - tval_s0 = fc/((sp * (np.sqrt((1/n_x)+(1/n_y))))+s0) + tval = fc / (sp * (np.sqrt((1 / n_x) + (1 / n_y)))) + tval_s0 = fc / ((sp * (np.sqrt((1 / n_x) + (1 / n_y)))) + s0) # Get p-values - pval = 2*(1-stats.t.cdf(np.abs(tval), n_x+n_y-2)) - pval_s0 = 2*(1-stats.t.cdf(np.abs(tval_s0), n_x+n_y-2)) + pval = 2 * (1 - stats.t.cdf(np.abs(tval), n_x + n_y - 2)) + pval_s0 = 2 * (1 - stats.t.cdf(np.abs(tval_s0), n_x + n_y - 2)) return [fc, tval, pval, tval_s0, pval_s0] @@ -71,11 +74,13 @@ def workflow_ttest(df, c1, c2, s0=1, parallelize=False): fold-change to be trusted. """ if parallelize: - res = df.swifter.progress_bar(False).apply(lambda row : perform_ttest(row[c1], row[c2], s0=s0), axis = 1) + res = df.swifter.progress_bar(False).apply( + lambda row: perform_ttest(row[c1], row[c2], s0=s0), axis=1 + ) else: - res = df.apply(lambda row : perform_ttest(row[c1], row[c2], s0=s0), axis = 1) + res = df.apply(lambda row: perform_ttest(row[c1], row[c2], s0=s0), axis=1) - res = pd.DataFrame(list(res), columns=['fc','tval','pval','tval_s0','pval_s0']) + res = pd.DataFrame(list(res), columns=["fc", "tval", "pval", "tval_s0", "pval_s0"]) df_real = pd.concat([df, res], axis=1) @@ -95,18 +100,28 @@ def workflow_permutation_tvals(df, c1, c2, s0=1, n_perm=2, parallelize=False): all_c = c1 + c2 all_c_rand = permutate_vars(all_c, n_rand=n_perm) res_perm = list() - for i in np.arange(0,len(all_c_rand)): + for i in np.arange(0, len(all_c_rand)): if parallelize: - res_i = df.swifter.progress_bar(False).apply(lambda row : perform_ttest(row[all_c_rand[i][0:len(c1)]], - row[all_c_rand[i][len(c1):len(c1)+len(c2)]], - s0=s0), - axis = 1) + res_i = df.swifter.progress_bar(False).apply( + lambda row: perform_ttest( + row[all_c_rand[i][0 : len(c1)]], + row[all_c_rand[i][len(c1) : len(c1) + len(c2)]], + s0=s0, + ), + axis=1, + ) else: - res_i = df.apply(lambda row : perform_ttest(row[all_c_rand[i][0:len(c1)]], - row[all_c_rand[i][len(c1):len(c1)+len(c2)]], - s0=s0), - axis=1) - res_i = pd.DataFrame(list(res_i), columns=['fc','tval','pval','tval_s0','pval_s0']) + res_i = df.apply( + lambda row: perform_ttest( + row[all_c_rand[i][0 : len(c1)]], + row[all_c_rand[i][len(c1) : len(c1) + len(c2)]], + s0=s0, + ), + axis=1, + ) + res_i = pd.DataFrame( + list(res_i), columns=["fc", "tval", "pval", "tval_s0", "pval_s0"] + ) res_perm.append(list(np.sort(np.abs(res_i.tval_s0.values)))) return res_perm @@ -127,7 +142,7 @@ def get_tstat_cutoff(res_real, t_perm_avg, delta): # between the observed and average random t-stat is # larger than the selected delta. t_max = t_real_abs[t_diff > delta] - if (t_max.shape[0] == 0): + if t_max.shape[0] == 0: t_max = np.ceil(np.max(t_real_abs)) else: t_max = np.min(t_max) @@ -193,7 +208,7 @@ def get_pi0(res_real, res_perm): t_perm_75 = np.percentile(t_perm_abs, 75) n_real_in_range = np.sum((t_real_abs >= t_perm_25) & (t_real_abs <= t_perm_75)) - pi0 = n_real_in_range/(0.5*len(t_real_abs)) + pi0 = n_real_in_range / (0.5 * len(t_real_abs)) # pi0 can maximally be 1 pi0 = np.min([pi0, 1]) @@ -207,10 +222,10 @@ def get_fdr(n_pos, n_false_pos, pi0): true positives. The number of false positives are adjusted by pi0, the proportion of true null (unaffected) genes in the data set. """ - n = n_false_pos*pi0 + n = n_false_pos * pi0 if n != 0: if n_pos != 0: - fdr = n/n_pos + fdr = n / n_pos else: fdr = 0 else: @@ -233,7 +248,7 @@ def estimate_fdr_stats(res_real, res_perm, delta): n_pos = get_positive_count(res_real_tval_s0=np.array(res_real.tval_s0), t_cut=t_cut) n_false_pos = get_false_positive_count(np.array(res_perm), t_cut=t_cut) pi0 = get_pi0(res_real, res_perm) - n_false_pos_corr = n_false_pos*pi0 + n_false_pos_corr = n_false_pos * pi0 fdr = get_fdr(n_pos, n_false_pos, pi0) return [t_cut, n_pos, n_false_pos, pi0, n_false_pos_corr, fdr] @@ -250,10 +265,12 @@ def get_fdr_stats_across_deltas(res_real, res_perm): break else: res_stats.append(res_d) - res_stats_df = pd.DataFrame(res_stats, - columns=['t_cut', 'n_pos', 'n_false_pos', 'pi0', 'n_false_pos_corr', 'fdr']) + res_stats_df = pd.DataFrame( + res_stats, + columns=["t_cut", "n_pos", "n_false_pos", "pi0", "n_false_pos_corr", "fdr"], + ) - return(res_stats_df) + return res_stats_df def get_tstat_limit(stats, fdr=0.01): @@ -261,14 +278,18 @@ def get_tstat_limit(stats, fdr=0.01): Function to get tval_s0 at the specified FDR. """ t_limit = np.min(stats[stats.fdr <= fdr].t_cut) - return(t_limit) + return t_limit def annotate_fdr_significance(res_real, stats, fdr=0.01): t_limit = np.min(stats[stats.fdr <= fdr].t_cut) - res_real['qval'] = [np.min(stats[stats.t_cut <= abs(x)].fdr) for x in res_real['tval_s0']] - res_real['FDR' + str(int(fdr*100)) + '%'] = ["sig" if abs(x) >= t_limit else "non_sig" for x in res_real['tval_s0']] - return(res_real) + res_real["qval"] = [ + np.min(stats[stats.t_cut <= abs(x)].fdr) for x in res_real["tval_s0"] + ] + res_real["FDR" + str(int(fdr * 100)) + "%"] = [ + "sig" if abs(x) >= t_limit else "non_sig" for x in res_real["tval_s0"] + ] + return res_real def perform_ttest_getMaxS(fc, s, s0, n_x, n_y): @@ -277,18 +298,25 @@ def perform_ttest_getMaxS(fc, s, s0, n_x, n_y): Called from within get_fdr_line. """ # Get t-values - tval = fc/s - tval_s0 = fc/(s+s0) + tval = fc / s + tval_s0 = fc / (s + s0) # Get p-values - pval = 2*(1-stats.t.cdf(np.abs(tval), n_x+n_y-2)) - pval_s0 = 2*(1-stats.t.cdf(np.abs(tval_s0), n_x+n_y-2)) + pval = 2 * (1 - stats.t.cdf(np.abs(tval), n_x + n_y - 2)) + pval_s0 = 2 * (1 - stats.t.cdf(np.abs(tval_s0), n_x + n_y - 2)) return [fc, tval, pval, tval_s0, pval_s0] -def get_fdr_line(t_limit, s0, n_x, n_y, plot=False, - fc_s=np.arange(0, 6, 0.01), s_s=np.arange(0.005, 6, 0.005)): +def get_fdr_line( + t_limit, + s0, + n_x, + n_y, + plot=False, + fc_s=np.arange(0, 6, 0.01), + s_s=np.arange(0.005, 6, 0.005), +): """ Function to get the fdr line for a volcano plot as specified tval_s0 limit, s0, n_x and n_y. @@ -303,7 +331,9 @@ def get_fdr_line(t_limit, s0, n_x, n_y, plot=False, svals[i] = s_s[j] pvals[i] = res_s[2] - s_df = pd.DataFrame(np.array([fc_s, svals, pvals]).T, columns=['fc_s','svals','pvals']) + s_df = pd.DataFrame( + np.array([fc_s, svals, pvals]).T, columns=["fc_s", "svals", "pvals"] + ) s_df = s_df[s_df.pvals != 1] s_df_neg = s_df.copy() @@ -311,27 +341,38 @@ def get_fdr_line(t_limit, s0, n_x, n_y, plot=False, s_df = s_df.append(s_df_neg) - if (plot): - fig = px.scatter(x=s_df.fc_s, - y=-np.log10(s_df.pvals), - template='simple_white') + if plot: + fig = px.scatter(x=s_df.fc_s, y=-np.log10(s_df.pvals), template="simple_white") fig.show() - return(s_df) + return s_df - -def perform_ttest_analysis(df, c1, c2, s0=1, n_perm=2, fdr=0.01, id_col='Genes', plot_fdr_line=False, parallelize=False): +def perform_ttest_analysis( + df, + c1, + c2, + s0=1, + n_perm=2, + fdr=0.01, + id_col="Genes", + plot_fdr_line=False, + parallelize=False, +): """ Workflow function for the entire T-test analysis including FDR estimation and visualizing a volcanoe plot. """ ttest_res = workflow_ttest(df, c1, c2, s0, parallelize=parallelize) - ttest_perm_res = workflow_permutation_tvals(df, c1, c2, s0, n_perm, parallelize=parallelize) + ttest_perm_res = workflow_permutation_tvals( + df, c1, c2, s0, n_perm, parallelize=parallelize + ) ttest_stats = get_fdr_stats_across_deltas(ttest_res, ttest_perm_res) - ttest_res = annotate_fdr_significance(res_real=ttest_res, stats=ttest_stats, fdr=fdr) + ttest_res = annotate_fdr_significance( + res_real=ttest_res, stats=ttest_stats, fdr=fdr + ) t_limit = get_tstat_limit(stats=ttest_stats, fdr=fdr) - return(ttest_res, t_limit) + return (ttest_res, t_limit) def perform_regression(y, X, s0): @@ -350,7 +391,7 @@ def perform_regression(y, X, s0): # Calculate mean squared error (MSE) of observed y vs. prediction # MSE = squared_error/degrees_of_freedom # degrees_of_freedom = number_of_samples - number_of_betas (including beta0 = intercept) - MSE = (sum((y-predictions)**2))/(len(newX)-len(newX.columns)) + MSE = (sum((y - predictions) ** 2)) / (len(newX) - len(newX.columns)) # Calculate t-values and p-values ts_b, ps_b = get_tstats(newX, betas, MSE) # Adjust the MSE by the minimum fold change that we trust (s0) @@ -359,7 +400,7 @@ def perform_regression(y, X, s0): ts_b_s0, ps_b_s0 = get_tstats(newX, betas, MSE_s0) betas_std = list() for i in np.arange(0, len(betas)): - betas_std.append(betas[i]*(get_std(np.array(newX)[:, i])/get_std(y))) + betas_std.append(betas[i] * (get_std(np.array(newX)[:, i]) / get_std(y))) betas_std = np.array(betas_std) return betas, betas_std, predictions, MSE, ts_b, ps_b, MSE_s0, ts_b_s0, ps_b_s0 @@ -369,14 +410,14 @@ def get_tstats(newX, betas, MSE): # This scales the error as estimated by MSE to each beta # (error on the betas might be different for different betas depending on # the variable) - var_b = MSE*(np.linalg.inv(np.dot(newX.T, newX)).diagonal()) + var_b = MSE * (np.linalg.inv(np.dot(newX.T, newX)).diagonal()) sd_b = np.sqrt(var_b) # Get t-values - ts_b = betas/sd_b + ts_b = betas / sd_b # Get p-values - #ps_b =[2*(1-stats.t.cdf(np.abs(i),len(newX)-len(newX.columns))) for i in ts_b] - #ps_b =[2*(1-nbs.t_cdf(np.abs(i),len(newX)-len(newX.columns),0,1)) for i in ts_b] - ps_b = get_cdf(ts_b, len(newX)-len(newX.columns)) + # ps_b =[2*(1-stats.t.cdf(np.abs(i),len(newX)-len(newX.columns))) for i in ts_b] + # ps_b =[2*(1-nbs.t_cdf(np.abs(i),len(newX)-len(newX.columns),0,1)) for i in ts_b] + ps_b = get_cdf(ts_b, len(newX) - len(newX.columns)) return ts_b, ps_b @@ -384,8 +425,8 @@ def get_tstats(newX, betas, MSE): def get_cdf(ts, df): pvals = [0.0][1:] for t in ts: - pvals.append(2*(1-nbs.t_cdf(np.abs(t), df, 0, 1))) - return (pvals) + pvals.append(2 * (1 - nbs.t_cdf(np.abs(t), df, 0, 1))) + return pvals def filter_nan(y, X): @@ -410,7 +451,7 @@ def get_min_vars(X): if n_vars > 2: min_vars.append(n_vars) else: - test_vals_0 = np.append(test_vals,[0,1]) # append 0 and 1 for counter + test_vals_0 = np.append(test_vals, [0, 1]) # append 0 and 1 for counter var_count = Counter(test_vals_0) min_vars.append(min(var_count.values())) @@ -422,14 +463,24 @@ def regression_workflow(y, X, s0): # Removed min_var filtering after standard scaling of variable. # @ToDo: Include sanity check that sufficient categories are covered! # The following counts the minimum number of observations for each covariate - #min_vars = get_min_vars(X_new) + # min_vars = get_min_vars(X_new) # A min(min_vars) value < 2 means essentially no values for at least one covariate were observed # A beta of zero and p-values of 1 are returned for these cases - #if min(min_vars) < 2: + # if min(min_vars) < 2: # betas, betas_std, tvals, pvals, tvals_s0, pvals_s0 = 0, 0, 0, 1, 0, 1 - #else: + # else: # betas, betas_std, predictions, MSE, tvals, pvals, MSE_s0, tvals_s0, pvals_s0 = perform_regression(np.array(y_new), np.array(X_new), s0) - betas, betas_std, predictions, MSE, tvals, pvals, MSE_s0, tvals_s0, pvals_s0 = perform_regression(np.array(y_new), np.array(X_new), s0) + ( + betas, + betas_std, + predictions, + MSE, + tvals, + pvals, + MSE_s0, + tvals_s0, + pvals_s0, + ) = perform_regression(np.array(y_new), np.array(X_new), s0) return betas, betas_std, tvals, pvals, tvals_s0, pvals_s0 @@ -442,28 +493,36 @@ def regression_workflow_permutation(y, X_rand, s0): return res_rand -def get_fdr_line_regression(t_limits, s0, X, plot = False, - fc_s = np.arange(0,6,0.01), s_s = np.arange(0.005,6,0.005)): +def get_fdr_line_regression( + t_limits, + s0, + X, + plot=False, + fc_s=np.arange(0, 6, 0.01), + s_s=np.arange(0.005, 6, 0.005), +): """ Function to get the fdr line for a volcano plot as specified tval_s0 limit, s0, n_x and n_y. """ - #pvals = [list(np.ones(len(fc_s)))] * X.shape[1] - pvals = [list(np.ones(len(fc_s))) for i in range(0,X.shape[1])] - #print(pvals) - #svals = [list(np.zeros(len(fc_s)))] * X.shape[1] - svals = [list(np.zeros(len(fc_s))) for i in range(0,X.shape[1])] - #print(svals) - for i in np.arange(0,len(fc_s)): - for j in np.arange(0,len(s_s)): + # pvals = [list(np.ones(len(fc_s)))] * X.shape[1] + pvals = [list(np.ones(len(fc_s))) for i in range(0, X.shape[1])] + # print(pvals) + # svals = [list(np.zeros(len(fc_s)))] * X.shape[1] + svals = [list(np.zeros(len(fc_s))) for i in range(0, X.shape[1])] + # print(svals) + for i in np.arange(0, len(fc_s)): + for j in np.arange(0, len(s_s)): res_s = perform_ttest_getMaxS_regression(fc=fc_s[i], s=s_s[j], s0=s0, X=X) - for k in np.arange(0,X.shape[1]): + for k in np.arange(0, X.shape[1]): t_limit = t_limits[k] if (res_s[k][3] >= t_limit) and (svals[k][i] < s_s[j]): svals[k][i] = s_s[j] pvals[k][i] = res_s[k][2] s_df_list = list() for k in np.arange(0, X.shape[1]): - s_df = pd.DataFrame(np.array([fc_s,svals[k],pvals[k]]).T, columns=['fc_s','svals','pvals']) + s_df = pd.DataFrame( + np.array([fc_s, svals[k], pvals[k]]).T, columns=["fc_s", "svals", "pvals"] + ) s_df = s_df[s_df.pvals != 1] s_df_neg = s_df.copy() @@ -471,15 +530,15 @@ def get_fdr_line_regression(t_limits, s0, X, plot = False, s_df = s_df.append(s_df_neg) - if (plot): - fig = px.scatter(x=s_df.fc_s, - y=-np.log10(s_df.pvals), - template='simple_white') + if plot: + fig = px.scatter( + x=s_df.fc_s, y=-np.log10(s_df.pvals), template="simple_white" + ) fig.show() s_df_list.append(s_df) - return(s_df_list) + return s_df_list def perform_ttest_getMaxS_regression(fc, s, s0, X): @@ -487,22 +546,26 @@ def perform_ttest_getMaxS_regression(fc, s, s0, X): Helper function to get ttest stats for specified standard errors s. Called from within get_fdr_line_regression. """ - newX = pd.DataFrame({"Constant":np.ones(len(X))}).join(pd.DataFrame(X)) - fc=np.repeat(fc,newX.shape[1]) - #print(fc) - var_b = s*(np.linalg.inv(np.dot(newX.T,newX)).diagonal()) + newX = pd.DataFrame({"Constant": np.ones(len(X))}).join(pd.DataFrame(X)) + fc = np.repeat(fc, newX.shape[1]) + # print(fc) + var_b = s * (np.linalg.inv(np.dot(newX.T, newX)).diagonal()) sd_b = np.sqrt(var_b) - ts_b = fc/sd_b - #ps_b =[2*(1-stats.t.cdf(np.abs(i),len(newX)-len(newX.columns))) for i in ts_b] - ps_b = get_cdf(ts_b, len(newX)-len(newX.columns)) - var_b_s0 = (s+s0)*(np.linalg.inv(np.dot(newX.T,newX)).diagonal()) + ts_b = fc / sd_b + # ps_b =[2*(1-stats.t.cdf(np.abs(i),len(newX)-len(newX.columns))) for i in ts_b] + ps_b = get_cdf(ts_b, len(newX) - len(newX.columns)) + var_b_s0 = (s + s0) * (np.linalg.inv(np.dot(newX.T, newX)).diagonal()) sd_b_s0 = np.sqrt(var_b_s0) - ts_b_s0 = fc/sd_b_s0 - #ps_b_s0 =[2*(1-stats.t.cdf(np.abs(i),len(newX)-len(newX.columns))) for i in ts_b_s0] - ps_b_s0 = get_cdf(ts_b_s0, len(newX)-len(newX.columns)) - res = [[fc[x], ts_b[x], ps_b[x], ts_b_s0[x], ps_b_s0[x]] for x in np.arange(1,newX.shape[1])] + ts_b_s0 = fc / sd_b_s0 + # ps_b_s0 =[2*(1-stats.t.cdf(np.abs(i),len(newX)-len(newX.columns))) for i in ts_b_s0] + ps_b_s0 = get_cdf(ts_b_s0, len(newX) - len(newX.columns)) + res = [ + [fc[x], ts_b[x], ps_b[x], ts_b_s0[x], ps_b_s0[x]] + for x in np.arange(1, newX.shape[1]) + ] return res + def generate_perms(n, n_rand, seed=42): """ Generate n_rand permutations of indeces ranging from 0 to n. @@ -511,9 +574,13 @@ def generate_perms(n, n_rand, seed=42): idx_v = np.arange(0, n) rand_v = list() n_rand_i = 0 - n_rand_max = math.factorial(n)-1 + n_rand_max = math.factorial(n) - 1 if n_rand_max <= n_rand: - print("{} random permutations cannot be created. The maximum of n_rand={} is used instead.".format(n_rand, n_rand_max)) + print( + "{} random permutations cannot be created. The maximum of n_rand={} is used instead.".format( + n_rand, n_rand_max + ) + ) n_rand = n_rand_max while n_rand_i < n_rand: rand_i = list(np.random.permutation(idx_v)) @@ -546,9 +613,18 @@ def permutate_multi_vars(X, rand_index, n_rand, seed=42): def get_res_parallel(y_i, X, s0): - betas, betas_std, tvals, pvals, tvals_s0, pvals_s0 = regression_workflow(y=y_i, X = X, s0 = s0) + betas, betas_std, tvals, pvals, tvals_s0, pvals_s0 = regression_workflow( + y=y_i, X=X, s0=s0 + ) res = pd.DataFrame() - res["fc"], res["fc_std"], res["tval"], res["pval"], res["tval_s0"], res["pval_s0"] = [betas, betas_std, tvals, pvals, tvals_s0, pvals_s0] + ( + res["fc"], + res["fc_std"], + res["tval"], + res["pval"], + res["tval_s0"], + res["pval_s0"], + ) = [betas, betas_std, tvals, pvals, tvals_s0, pvals_s0] return res @@ -557,10 +633,19 @@ def get_perm_res_parallel(y_i, X_rand, s0): return res_perm_list -def full_regression_analysis(quant_data, annotation, covariates, sample_column='sample_name', n_permutations=4, fdr=0.05, s0=0.05, seed=42): +def full_regression_analysis( + quant_data, + annotation, + covariates, + sample_column="sample_name", + n_permutations=4, + fdr=0.05, + s0=0.05, + seed=42, +): data_cols = annotation[sample_column].values quant_data = quant_data.dropna().reset_index(drop=True) - y = quant_data[data_cols].to_numpy().astype('float') + y = quant_data[data_cols].to_numpy().astype("float") # @ToDo make sure that columns are sorted correctly!!! X = np.array(annotation[covariates]) @@ -568,15 +653,21 @@ def full_regression_analysis(quant_data, annotation, covariates, sample_column=' X_scaled = StandardScaler().fit_transform(X) num_cores = multiprocessing.cpu_count() - res_list = Parallel(n_jobs=num_cores-1)(delayed(get_res_parallel)(y_i=y_i, X=X_scaled, s0=s0) for y_i in y) + res_list = Parallel(n_jobs=num_cores - 1)( + delayed(get_res_parallel)(y_i=y_i, X=X_scaled, s0=s0) for y_i in y + ) t_limit_dict = {} for test_index in np.arange(0, len(covariates)): test_covariate = covariates[test_index] print(test_covariate) - X_rand = permutate_multi_vars(X_scaled, rand_index=test_index, n_rand=n_permutations, seed=seed) - res_perm_list = Parallel(n_jobs=num_cores-1)(delayed(get_perm_res_parallel)(y_i=y_i, X_rand=X_rand, s0=s0) for y_i in y) + X_rand = permutate_multi_vars( + X_scaled, rand_index=test_index, n_rand=n_permutations, seed=seed + ) + res_perm_list = Parallel(n_jobs=num_cores - 1)( + delayed(get_perm_res_parallel)(y_i=y_i, X_rand=X_rand, s0=s0) for y_i in y + ) i = test_index + 1 res_i = [r.iloc[[i]] for r in res_list] @@ -584,9 +675,9 @@ def full_regression_analysis(quant_data, annotation, covariates, sample_column=' # get tvals_s0 list of permutations for covariate i res_i_rand = [[0] * len(res_perm_list) for i in range(len(res_perm_list[0]))] - for a in np.arange(0,len(res_perm_list)): + for a in np.arange(0, len(res_perm_list)): for b in np.arange(0, len(res_perm_list[a])): - #print(res_perm_list[a][b][3]) + # print(res_perm_list[a][b][3]) res_i_rand[b][a] = res_perm_list[a][b][4][i] res_i_rand = [list(np.sort(np.abs(r))) for r in res_i_rand] @@ -596,19 +687,25 @@ def full_regression_analysis(quant_data, annotation, covariates, sample_column=' t_limit_dict[test_covariate] = t_limit_i # @ToDo: This multiple testing should potentially be done across all covariates together? - res_i['qval_BH'] = multipletests(res_i.pval, method='fdr_bh')[1] - res_i['BH_FDR ' + str(int(fdr*100)) + '%'] = ["sig" if abs(x)<=fdr else "non_sig" for x in res_i["qval_BH"]] - res_i['qval_BH_s0'] = multipletests(res_i.pval_s0, method='fdr_bh')[1] - res_i['BH_FDR_s0 ' + str(int(fdr*100)) + '%'] = ["sig" if abs(x)<=fdr else "non_sig" for x in res_i["qval_BH_s0"]] + res_i["qval_BH"] = multipletests(res_i.pval, method="fdr_bh")[1] + res_i["BH_FDR " + str(int(fdr * 100)) + "%"] = [ + "sig" if abs(x) <= fdr else "non_sig" for x in res_i["qval_BH"] + ] + res_i["qval_BH_s0"] = multipletests(res_i.pval_s0, method="fdr_bh")[1] + res_i["BH_FDR_s0 " + str(int(fdr * 100)) + "%"] = [ + "sig" if abs(x) <= fdr else "non_sig" for x in res_i["qval_BH_s0"] + ] res_i = res_i.add_prefix(covariates[test_index] + "_") - quant_data = pd.concat([quant_data.reset_index(drop=True), res_i.reset_index(drop=True)], axis=1) + quant_data = pd.concat( + [quant_data.reset_index(drop=True), res_i.reset_index(drop=True)], axis=1 + ) return [quant_data, t_limit_dict] -def add_random_covariate(annotation, name='random', n_random=50, seed=42): +def add_random_covariate(annotation, name="random", n_random=50, seed=42): annotation_test = annotation.copy() annotation_test.reset_index(drop=True, inplace=True) annotation_test[name] = 0 @@ -619,125 +716,167 @@ def add_random_covariate(annotation, name='random', n_random=50, seed=42): def plot_evaluate_seed_and_perm(df, covariates): - config = {'toImageButtonOptions': {'format': 'svg', - 'filename': 'permutation_test', - 'scale': 1 - } - } + config = { + "toImageButtonOptions": { + "format": "svg", + "filename": "permutation_test", + "scale": 1, + } + } for c in covariates: - fig = px.line(df, x="permutations", - y=c, - line_dash="seed", - line_group="seed", - template="simple_white", - color_discrete_sequence=['lightgrey']) - fig.update_traces(mode='lines+markers') + fig = px.line( + df, + x="permutations", + y=c, + line_dash="seed", + line_group="seed", + template="simple_white", + color_discrete_sequence=["lightgrey"], + ) + fig.update_traces(mode="lines+markers") fig.update_layout(width=620, height=350) fig.show(config=config) -def evaluate_seed_and_perm(quant_data, - annotation, - covariates, - perms, - seeds, - sample_column='sample_name', - fdr=0.05, - s0=0.05): - resDF = pd.DataFrame({'seed': np.repeat(seeds, len(perms)), - 'permutations': np.tile(perms, len(seeds))}) - resDF[covariates] = pd.DataFrame([np.repeat(0, len(covariates))], - index=resDF.index) - - for i in np.arange(0,resDF.shape[0]): - res, tlim = full_regression_analysis(quant_data=quant_data, - annotation=annotation, - covariates=covariates, - n_permutations=resDF.permutations[i], - sample_column=sample_column, - fdr=fdr, - s0=s0, - seed=resDF.seed[i]) +def evaluate_seed_and_perm( + quant_data, + annotation, + covariates, + perms, + seeds, + sample_column="sample_name", + fdr=0.05, + s0=0.05, +): + resDF = pd.DataFrame( + { + "seed": np.repeat(seeds, len(perms)), + "permutations": np.tile(perms, len(seeds)), + } + ) + resDF[covariates] = pd.DataFrame([np.repeat(0, len(covariates))], index=resDF.index) + + for i in np.arange(0, resDF.shape[0]): + res, tlim = full_regression_analysis( + quant_data=quant_data, + annotation=annotation, + covariates=covariates, + n_permutations=resDF.permutations[i], + sample_column=sample_column, + fdr=fdr, + s0=s0, + seed=resDF.seed[i], + ) for c in covariates: - resDF.loc[i,c] = res[res[c + "_FDR " + str(int(fdr*100)) + "%"] == "sig"].shape[0] + resDF.loc[i, c] = res[ + res[c + "_FDR " + str(int(fdr * 100)) + "%"] == "sig" + ].shape[0] plot_evaluate_seed_and_perm(resDF, covariates=covariates) return resDF def plot_evaluate_s0s(df, covariates): for c in covariates: - fig = px.line(df, x="s0", y=c, title=c, template="simple_white", color_discrete_sequence=['lightgrey']) - fig.update_traces(mode='lines+markers') + fig = px.line( + df, + x="s0", + y=c, + title=c, + template="simple_white", + color_discrete_sequence=["lightgrey"], + ) + fig.update_traces(mode="lines+markers") fig.update_layout(width=800, height=500) fig.show() -def evaluate_s0s(quant_data, - annotation, - covariates, - s0s, - sample_column='sample_name', - n_permutations=5, - seed=42, - fdr=0.01): - resDF = pd.DataFrame({'s0':s0s}) +def evaluate_s0s( + quant_data, + annotation, + covariates, + s0s, + sample_column="sample_name", + n_permutations=5, + seed=42, + fdr=0.01, +): + resDF = pd.DataFrame({"s0": s0s}) resDF[covariates] = pd.DataFrame([np.repeat(0, len(covariates))], index=resDF.index) - for i in np.arange(0,resDF.shape[0]): - res, tlim = full_regression_analysis(quant_data=quant_data, - annotation=annotation, - covariates=covariates, - sample_column=sample_column, - n_permutations=n_permutations, - fdr=fdr, - s0=resDF.s0[i], - seed=seed) + for i in np.arange(0, resDF.shape[0]): + res, tlim = full_regression_analysis( + quant_data=quant_data, + annotation=annotation, + covariates=covariates, + sample_column=sample_column, + n_permutations=n_permutations, + fdr=fdr, + s0=resDF.s0[i], + seed=seed, + ) for c in covariates: - resDF.loc[i,c] = res[res[c + "_FDR " + str(int(fdr*100)) + "%"] == "sig"].shape[0] + resDF.loc[i, c] = res[ + res[c + "_FDR " + str(int(fdr * 100)) + "%"] == "sig" + ].shape[0] plot_evaluate_s0s(resDF, covariates=covariates) return resDF -def plot_pval_dist(df, covariates, mode='separate'): - config = {'toImageButtonOptions': {'format': 'svg', - 'filename': 'pvalue_histogram', - 'scale': 1 - } - } - if (mode == 'separate'): +def plot_pval_dist(df, covariates, mode="separate"): + config = { + "toImageButtonOptions": { + "format": "svg", + "filename": "pvalue_histogram", + "scale": 1, + } + } + if mode == "separate": for c in covariates: - fig = px.histogram(df, - x=c+"_pval", - title=c, - nbins=50, - template='simple_white', - color_discrete_sequence=['lightgrey']) + fig = px.histogram( + df, + x=c + "_pval", + title=c, + nbins=50, + template="simple_white", + color_discrete_sequence=["lightgrey"], + ) fig.update_layout(width=400, height=300) fig.show(config=config) - elif (mode == 'joined'): + elif mode == "joined": df_cov = pd.DataFrame() for c in covariates: - df_c = pd.DataFrame({'p-value': df[c+"_pval"], 'covariate': c}) + df_c = pd.DataFrame({"p-value": df[c + "_pval"], "covariate": c}) df_cov = pd.concat([df_cov, df_c]) - fig = px.histogram(df_cov, x='p-value', - color='covariate', - barmode='overlay', - opacity=0.6, - nbins=50, - template='simple_white') + fig = px.histogram( + df_cov, + x="p-value", + color="covariate", + barmode="overlay", + opacity=0.6, + nbins=50, + template="simple_white", + ) fig.update_layout(width=620, height=350) fig.show(config=config) else: - raise ValueError("The mode parameter needs to be either 'separate' or 'joined'.") + raise ValueError( + "The mode parameter needs to be either 'separate' or 'joined'." + ) def plot_beta_dist(df, covariates): for c in covariates: - fig = px.histogram(df, x=c+"_fc", title=c, template='simple_white', color_discrete_sequence=['lightgrey']) + fig = px.histogram( + df, + x=c + "_fc", + title=c, + template="simple_white", + color_discrete_sequence=["lightgrey"], + ) fig.update_layout(width=800, height=500) fig.show() @@ -751,13 +890,18 @@ def get_replacement_vals(df, threshold, mean_all, sd_all, ds_f): rep = [] elif df.percent_valid_vals > threshold: # print(70) - rep = np.random.normal(df.int_mean-(ds_f*df.int_sd), df.int_sd, df.invalid_vals) + rep = np.random.normal( + df.int_mean - (ds_f * df.int_sd), df.int_sd, df.invalid_vals + ) else: # print(0) - rep = np.random.normal(mean_all-(ds_f*sd_all), sd_all, df.invalid_vals) - return(rep) + rep = np.random.normal(mean_all - (ds_f * sd_all), sd_all, df.invalid_vals) + return rep + -def impute_missing_values(data, percent_impute=20, percent_self_impute=70, downshift_factor=1.8): +def impute_missing_values( + data, percent_impute=20, percent_self_impute=70, downshift_factor=1.8 +): """ Function for missing value imputation. Proteins with less than 'percent_impute' valid values are removed. @@ -769,11 +913,15 @@ def impute_missing_values(data, percent_impute=20, percent_self_impute=70, downs of the imputed distribution is shifted. """ - data['int_mean'] = data.filter(regex=("Quantity")).mean(axis=1) - data['int_sd'] = data.filter(regex=("Quantity")).std(axis=1) - data['valid_vals'] = data.filter(regex=("Quantity")).count(axis=1) - data['invalid_vals'] = data.filter(regex=("Quantity")).shape[1]-data.filter(regex=("Quantity")).count(axis=1) - data['percent_valid_vals'] = 100/data.filter(regex=("Quantity")).shape[1]*data['valid_vals'] + data["int_mean"] = data.filter(regex=("Quantity")).mean(axis=1) + data["int_sd"] = data.filter(regex=("Quantity")).std(axis=1) + data["valid_vals"] = data.filter(regex=("Quantity")).count(axis=1) + data["invalid_vals"] = data.filter(regex=("Quantity")).shape[1] - data.filter( + regex=("Quantity") + ).count(axis=1) + data["percent_valid_vals"] = ( + 100 / data.filter(regex=("Quantity")).shape[1] * data["valid_vals"] + ) data = data[data.percent_valid_vals >= percent_impute] @@ -782,7 +930,14 @@ def impute_missing_values(data, percent_impute=20, percent_self_impute=70, downs nan_idx = np.where(data.isna()) - replacement = data.apply(get_replacement_vals, threshold=percent_self_impute, mean_all=overall_mean, sd_all=overall_sd, ds_f = downshift_factor, axis=1) + replacement = data.apply( + get_replacement_vals, + threshold=percent_self_impute, + mean_all=overall_mean, + sd_all=overall_sd, + ds_f=downshift_factor, + axis=1, + ) replacement = [val for sublist in replacement for val in sublist] for i in np.arange(0, len(nan_idx[0])): diff --git a/alphastats/plots/ClusterMap.py b/alphastats/plots/ClusterMap.py index f3fbffa8..b2cc1b69 100644 --- a/alphastats/plots/ClusterMap.py +++ b/alphastats/plots/ClusterMap.py @@ -5,14 +5,7 @@ class ClusterMap(PlotUtils): - def __init__( - self, - dataset, - label_bar, - only_significant, - group, - subgroups - ): + def __init__(self, dataset, label_bar, only_significant, group, subgroups): self.dataset = dataset self.label_bar = label_bar self.only_significant = only_significant @@ -22,13 +15,14 @@ def __init__( self._prepare_df() self._plot() - def _prepare_df(self): df = self.dataset.mat.loc[:, (self.dataset.mat != 0).any(axis=0)] if self.group is not None and self.subgroups is not None: metadata_df = self.dataset.metadata[ - self.dataset.metadata[self.group].isin(self.subgroups + [self.dataset.sample]) + self.dataset.metadata[self.group].isin( + self.subgroups + [self.dataset.sample] + ) ] samples = metadata_df[self.dataset.sample] df = df.filter(items=samples, axis=0) @@ -44,18 +38,17 @@ def _prepare_df(self): df = df[significant_proteins] if self.label_bar is not None: - self._create_label_bar( - metadata_df - ) + self._create_label_bar(metadata_df) - self.prepared_df = self.dataset.mat.loc[:, (self.dataset.mat != 0).any(axis=0)].transpose() - + self.prepared_df = self.dataset.mat.loc[ + :, (self.dataset.mat != 0).any(axis=0) + ].transpose() def _plot(self): fig = sns.clustermap(self.prepared_df, col_colors=self.label_bar) if self.label_bar is not None: - fig = self._add_label_bar(fig) + fig = self._add_label_bar(fig) # set attributes setattr(fig, "plotting_data", self.prepared_df) @@ -66,10 +59,10 @@ def _plot(self): def _add_label_bar(self, fig): for label in self.s.unique(): - fig.ax_col_dendrogram.bar( - 0, 0, color=self.lut[label], label=label, linewidth=0 - ) - fig.ax_col_dendrogram.legend(loc="center", ncol=6) + fig.ax_col_dendrogram.bar( + 0, 0, color=self.lut[label], label=label, linewidth=0 + ) + fig.ax_col_dendrogram.legend(loc="center", ncol=6) return fig def _create_label_bar(self, metadata_df): @@ -88,5 +81,3 @@ def _create_label_bar(self, metadata_df): colors = sns.light_palette(random.choice(colorway), len(su)) self.lut = dict(zip(su, colors)) self.label_bar = self.s.map(self.lut) - - diff --git a/alphastats/plots/DimensionalityReduction.py b/alphastats/plots/DimensionalityReduction.py index 5bf9570d..8a7d2282 100644 --- a/alphastats/plots/DimensionalityReduction.py +++ b/alphastats/plots/DimensionalityReduction.py @@ -110,12 +110,12 @@ def _tsne(self, **kwargs): def _umap(self): - # TODO umap import is reallly buggy + # TODO umap import is reallly buggy try: import umap.umap_ as umap except ModuleNotFoundError: import umap - + umap_2d = umap.UMAP(n_components=2, init="random", random_state=0) self.components = umap_2d.fit_transform(self.prepared_df) self.labels = { @@ -151,7 +151,7 @@ def _plot(self, sample_names, group_color): figure_object=fig, plotting_data=pd.DataFrame(components), method=self.method, - preprocessing_info=self.dataset.preprocessing_info + preprocessing_info=self.dataset.preprocessing_info, ) # draw circles around plotted groups diff --git a/alphastats/plots/IntensityPlot.py b/alphastats/plots/IntensityPlot.py index 5c0540c2..07f570b7 100644 --- a/alphastats/plots/IntensityPlot.py +++ b/alphastats/plots/IntensityPlot.py @@ -1,4 +1,3 @@ - import logging import scipy import numpy as np @@ -9,7 +8,8 @@ class IntensityPlot(PlotUtils): - def __init__(self, + def __init__( + self, dataset, protein_id, group, @@ -28,7 +28,6 @@ def __init__(self, self._prepare_data() self._plot() - @staticmethod def _add_significance(plot): @@ -52,13 +51,13 @@ def _add_significance(plot): if pvalue < 0.001: significance_level = "***" pvalue_text = "p<0.001" - + elif pvalue < 0.01: significance_level = "**" - + elif pvalue < 0.05: significance_level = "*" - + else: significance_level = "-" @@ -100,32 +99,52 @@ def _add_significance(plot): plot.update_layout(width=600, height=700) return plot - + def _prepare_data(self): #  TODO use difflib to find similar ProteinId if ProteinGroup is not present - df = self.dataset.mat[[self.protein_id]].reset_index().rename(columns={"index": self.dataset.sample}) + df = ( + self.dataset.mat[[self.protein_id]] + .reset_index() + .rename(columns={"index": self.dataset.sample}) + ) df = df.merge(self.dataset.metadata, how="inner", on=[self.dataset.sample]) if self.subgroups is not None: df = df[df[self.group].isin(self.subgroups)] - self.y_label = self.protein_id + " - " + self.dataset.intensity_column.replace("[sample]", "") + self.y_label = ( + self.protein_id + + " - " + + self.dataset.intensity_column.replace("[sample]", "") + ) self.prepared_df = df def _plot(self): if self.method == "violin": fig = px.violin( - self.prepared_df, y=self.protein_id, x=self.group, color=self.group, labels={self.protein_id: self.y_label} + self.prepared_df, + y=self.protein_id, + x=self.group, + color=self.group, + labels={self.protein_id: self.y_label}, ) elif self.method == "box": fig = px.box( - self.prepared_df, y=self.protein_id, x=self.group, color=self.group, labels={self.protein_id: self.y_label} + self.prepared_df, + y=self.protein_id, + x=self.group, + color=self.group, + labels={self.protein_id: self.y_label}, ) elif self.method == "scatter": fig = px.scatter( - self.prepared_df, y=self.protein_id, x=self.group, color=self.group, labels={self.protein_id: self.y_label} + self.prepared_df, + y=self.protein_id, + x=self.group, + color=self.group, + labels={self.protein_id: self.y_label}, ) else: @@ -142,9 +161,10 @@ def _plot(self): fig = plotly_object(fig) fig = self._update_figure_attributes( - figure_object=fig, plotting_data= self.prepared_df, preprocessing_info=self.dataset.preprocessing_info, method=self.method + figure_object=fig, + plotting_data=self.prepared_df, + preprocessing_info=self.dataset.preprocessing_info, + method=self.method, ) self.plot = fig - - diff --git a/alphastats/plots/PlotUtils.py b/alphastats/plots/PlotUtils.py index 990dcbca..12fd90d8 100644 --- a/alphastats/plots/PlotUtils.py +++ b/alphastats/plots/PlotUtils.py @@ -2,6 +2,7 @@ import seaborn as sns import plotly.graph_objects as go + class PlotUtils: def __init__(self) -> None: pass @@ -20,7 +21,9 @@ def _update_colors_plotly(fig, color_dict): # convert dict back to plotly figure return go.Figure(fig_dict) - def _update_figure_attributes(self, figure_object, plotting_data, preprocessing_info, method=None): + def _update_figure_attributes( + self, figure_object, plotting_data, preprocessing_info, method=None + ): setattr(figure_object, "plotting_data", plotting_data) setattr(figure_object, "preprocessing", preprocessing_info) setattr(figure_object, "method", method) diff --git a/alphastats/plots/VolcanoPlot.py b/alphastats/plots/VolcanoPlot.py index 3f10d766..c4879be3 100644 --- a/alphastats/plots/VolcanoPlot.py +++ b/alphastats/plots/VolcanoPlot.py @@ -11,12 +11,20 @@ class VolcanoPlot(PlotUtils): def __init__( - self, dataset, group1, group2, - column=None, method=None, - labels=None, min_fc=None, - alpha=None, draw_line=None, - plot=True, perm=100, fdr=0.05 - ): + self, + dataset, + group1, + group2, + column=None, + method=None, + labels=None, + min_fc=None, + alpha=None, + draw_line=None, + plot=True, + perm=100, + fdr=0.05, + ): self.dataset = dataset self.group1 = group1 self.group2 = group2 @@ -30,9 +38,9 @@ def __init__( self.hover_data = None self.res = None self.pvalue_column = None - self.perm=perm + self.perm = perm self._check_input() - + if plot: self._perform_differential_expression_analysis() self._annotate_result_df() @@ -57,8 +65,8 @@ def _update(self, updated_attributes): """ update attributes using dict """ - for key,value in updated_attributes.items(): - setattr(self,key,value) + for key, value in updated_attributes.items(): + setattr(self, key, value) @ignore_warning(UserWarning) @ignore_warning(RuntimeWarning) @@ -74,10 +82,10 @@ def _perform_differential_expression_analysis(self): elif self.method == "anova": self._anova() - + elif self.method == "sam": self._sam() - + # elif self.method == "Multi Covariates": # raise NotImplementedError @@ -91,28 +99,42 @@ def _perform_differential_expression_analysis(self): def _sam_calculate_fdr_line(self): from alphastats.multicova import multicova - self.fdr_line= multicova.get_fdr_line( - t_limit=self.tlim_ttest, - s0=0.05, - n_x=len(list(self.dataset.metadata[self.dataset.metadata[self.column]==self.group1][self.dataset.sample])), - n_y=len(list(self.dataset.metadata[self.dataset.metadata[self.column]==self.group2][self.dataset.sample])), - fc_s = np.arange(0,np.max(np.abs(self.res.log2fc)),np.max(np.abs(self.res.log2fc))/200), - s_s = np.arange(0.005, 6, 0.0025), - plot=False - ) - + self.fdr_line = multicova.get_fdr_line( + t_limit=self.tlim_ttest, + s0=0.05, + n_x=len( + list( + self.dataset.metadata[ + self.dataset.metadata[self.column] == self.group1 + ][self.dataset.sample] + ) + ), + n_y=len( + list( + self.dataset.metadata[ + self.dataset.metadata[self.column] == self.group2 + ][self.dataset.sample] + ) + ), + fc_s=np.arange( + 0, + np.max(np.abs(self.res.log2fc)), + np.max(np.abs(self.res.log2fc)) / 200, + ), + s_s=np.arange(0.005, 6, 0.0025), + plot=False, + ) + @lru_cache(maxsize=20) def _sam(self): from alphastats.multicova import multicova - print( - "Calculating t-test and permuation based FDR (SAM)... " - ) + print("Calculating t-test and permuation based FDR (SAM)... ") transposed = self.dataset.mat.transpose() if self.dataset.preprocessing_info["Normalization"] is None: - # needs to be lpog2 transformed for fold change calculations + # needs to be lpog2 transformed for fold change calculations transposed = transposed.transform(lambda x: np.log2(x)) transposed[self.dataset.index_column] = transposed.index @@ -120,23 +142,40 @@ def _sam(self): res_ttest, tlim_ttest = multicova.perform_ttest_analysis( transposed, - c1 =list(self.dataset.metadata[self.dataset.metadata[self.column]==self.group1][self.dataset.sample]), - c2 =list(self.dataset.metadata[self.dataset.metadata[self.column]==self.group2][self.dataset.sample]), - s0=0.05, + c1=list( + self.dataset.metadata[ + self.dataset.metadata[self.column] == self.group1 + ][self.dataset.sample] + ), + c2=list( + self.dataset.metadata[ + self.dataset.metadata[self.column] == self.group2 + ][self.dataset.sample] + ), + s0=0.05, n_perm=self.perm, fdr=self.fdr, id_col=self.dataset.index_column, - parallelize=True + parallelize=True, ) - - fdr_column = "FDR" + str(int(self.fdr*100)) + "%" - self.res = res_ttest[[self.dataset.index_column, 'fc', 'tval', 'pval', 'tval_s0', 'pval_s0', 'qval']] + + fdr_column = "FDR" + str(int(self.fdr * 100)) + "%" + self.res = res_ttest[ + [ + self.dataset.index_column, + "fc", + "tval", + "pval", + "tval_s0", + "pval_s0", + "qval", + ] + ] self.res["log2fc"] = res_ttest["fc"] self.res["FDR"] = res_ttest[fdr_column] self.tlim_ttest = tlim_ttest self.pvalue_column = "pval" - @lru_cache(maxsize=20) def _wald(self): @@ -182,7 +221,9 @@ def _anova(self): ][self.dataset.sample].tolist() mat_transpose = self.dataset.mat.transpose() - fc = self.dataset._calculate_foldchange(mat_transpose, group1_samples, group2_samples) + fc = self.dataset._calculate_foldchange( + mat_transpose, group1_samples, group2_samples + ) #  check how column is ordered self.pvalue_column = self.group1 + " vs. " + self.group2 + " Tukey Test" @@ -190,7 +231,9 @@ def _anova(self): if self.pvalue_column not in result_df.columns: self.pvalue_column = self.group2 + " vs. " + self.group1 + " Tukey Test" - self.res = result_df.reset_index().merge(fc.reset_index(), on=self.dataset.index_column) + self.res = result_df.reset_index().merge( + fc.reset_index(), on=self.dataset.index_column + ) def _add_hover_data_columns(self): # additional labeling with gene names @@ -199,13 +242,14 @@ def _add_hover_data_columns(self): if self.dataset.gene_names is not None: self.res = pd.merge( self.res, - self.dataset.rawinput[[self.dataset.gene_names, self.dataset.index_column]], + self.dataset.rawinput[ + [self.dataset.gene_names, self.dataset.index_column] + ], on=self.dataset.index_column, how="left", ) self.hover_data.append(self.dataset.gene_names) - def _annotate_result_df(self): """ convert pvalue to log10 @@ -213,15 +257,17 @@ def _annotate_result_df(self): """ self.res = self.res[(self.res["log2fc"] < 10) & (self.res["log2fc"] > -10)] self.res["-log10(p-value)"] = -np.log10(self.res[self.pvalue_column]) - + self.alpha = -np.log10(self.alpha) # add color variable to plot if self.method != "sam": - + condition = [ - (self.res["log2fc"] < -self.min_fc) & (self.res["-log10(p-value)"] > self.alpha), - (self.res["log2fc"] > self.min_fc) & (self.res["-log10(p-value)"] > self.alpha), + (self.res["log2fc"] < -self.min_fc) + & (self.res["-log10(p-value)"] > self.alpha), + (self.res["log2fc"] > self.min_fc) + & (self.res["-log10(p-value)"] > self.alpha), ] else: @@ -231,10 +277,8 @@ def _annotate_result_df(self): (self.res["log2fc"] > 0) & (self.res["FDR"] == "sig"), ] - value = ["down", "up"] - self.res["color"] = np.select(condition, value, default="non_sig") - + self.res["color"] = np.select(condition, value, default="non_sig") def _add_labels_plot(self): """ @@ -280,23 +324,26 @@ def _draw_fdr_line(self): Draw fdr line if SAM was applied """ self._sam_calculate_fdr_line() - - self.plot.add_trace(go.Scatter( - x=self.fdr_line[self.fdr_line.fc_s > 0].fc_s, - y=-np.log10(self.fdr_line[self.fdr_line.fc_s > 0].pvals), - line_color="black", - line_shape='spline', - showlegend=False) + + self.plot.add_trace( + go.Scatter( + x=self.fdr_line[self.fdr_line.fc_s > 0].fc_s, + y=-np.log10(self.fdr_line[self.fdr_line.fc_s > 0].pvals), + line_color="black", + line_shape="spline", + showlegend=False, + ) ) - self.plot.add_trace(go.Scatter( - x=self.fdr_line[self.fdr_line.fc_s < 0].fc_s, - y=-np.log10(self.fdr_line[self.fdr_line.fc_s < 0].pvals), - line_color="black", - line_shape='spline', - showlegend=False) + self.plot.add_trace( + go.Scatter( + x=self.fdr_line[self.fdr_line.fc_s < 0].fc_s, + y=-np.log10(self.fdr_line[self.fdr_line.fc_s < 0].pvals), + line_color="black", + line_shape="spline", + showlegend=False, + ) ) - def _plot(self): self.plot = px.scatter( self.res, @@ -305,14 +352,14 @@ def _plot(self): color="color", hover_data=self.hover_data, ) - + # update coloring color_dict = {"non_sig": "#404040", "up": "#B65EAF", "down": "#009599"} self.plot = self._update_colors_plotly(self.plot, color_dict=color_dict) if self.labels: self._add_labels_plot() - + if self.draw_line: if self.method == "sam": self._draw_fdr_line() @@ -325,11 +372,8 @@ def _plot(self): #  save plotting data in figure object self.plot = plotly_object(self.plot) self.plot = self._update_figure_attributes( - figure_object=self.plot, - plotting_data=self.res, - preprocessing_info=self.dataset.preprocessing_info, - method=self.method + figure_object=self.plot, + plotting_data=self.res, + preprocessing_info=self.dataset.preprocessing_info, + method=self.method, ) - - - diff --git a/alphastats/statistics/MultiCovaAnalysis.py b/alphastats/statistics/MultiCovaAnalysis.py index fa953c11..a24a177b 100644 --- a/alphastats/statistics/MultiCovaAnalysis.py +++ b/alphastats/statistics/MultiCovaAnalysis.py @@ -1,58 +1,77 @@ - - class MultiCovaAnalysis: - def __init__(self, dataset,covariates, n_permutations=3, fdr=0.05, s0=0.05, subset=None): + def __init__( + self, + dataset, + covariates: list, + n_permutations: int = 3, + fdr: float = 0.05, + s0: float = 0.05, + subset: dict = None, + ): self.dataset = dataset self.covariates = covariates - self.n_permutatons = n_permutations + self.n_permutations = n_permutations self.fdr = fdr self.s0 = s0 self.subset = subset - if len(self.covariates) == 0: - print("Covariates are invalid for analysis.") - return - + self._subset_metadata() + self._check_covariat_input() + self._check_na_values() + self._prepare_matrix() + def _subset_metadata(self): if self.subset is not None: - # dict structure {"column_name": ["group1", "group2"]} + # dict structure {"column_name": ["group1", "group2"]} subset_column = list(self.subset.keys())[0] groups = self.subset.get(subset_column) - self.metadata = self.dataset.metadata[self.dataset.metadata[subset_column].isin(groups)] + self.metadata = self.dataset.metadata[ + self.dataset.metadata[subset_column].isin(groups) + ] else: self.metadata = self.dataset.metadata - + def _check_covariat_input(self): - # check whether covariates in metadata column - misc_covariates = list(set(self.metadata.columns.to_list()) - set(self.covariates)) - if len(misc_covariates)> 0: + #  check whether covariates in metadata column + misc_covariates = list( + set(self.metadata.columns.to_list()) - set(self.covariates) + ) + if len(misc_covariates) > 0: Warning(f"Covariates: {misc_covariates} are not found in Metadata.") - self.covariates = filter(lambda i: i not in misc_covariates, self.covariates) - + self.covariates = filter( + lambda i: i not in misc_covariates, self.covariates + ) def _check_na_values(self): for covariate in self.covariates: - if metadata[covariate].isna().any(): + if self._prepare_matrixmetadata[covariate].isna().any(): self.covariates.remove(covariate) - Warning(f"Covariate: {covariate} contains missing values" + - f"in metadata and will not be used for analysis.") + Warning( + f"Covariate: {covariate} contains missing values" + + f"in metadata and will not be used for analysis." + ) def _prepare_matrix(self): transposed = self.dataset.mat.transpose() transposed[self.dataset.index_column] = transposed.index transposed = transposed.reset_index(drop=True) self.transposed = transposed[self.metadata[self.dataset.sample].to_list()] - + def calculate(self): from alphastats.multicova import multicova + + if len(self.covariates) == 0: + print("Covariates are invalid for analysis.") + return + res, tlim = multicova.full_regression_analysis( - quant_data = self.transposed, - annotation = self.metadata, - covariates = self.covariates, - sample_column = self.sample, + quant_data=self.transposed, + annotation=self.metadata, + covariates=self.covariates, + sample_column=self.dataset.sample, n_permutations=self.n_permutations, - fdr=self.fdr, - s0=self.s0 + fdr=self.fdr, + s0=self.s0, ) - return res \ No newline at end of file + return res diff --git a/alphastats/utils.py b/alphastats/utils.py index 347a5798..fdd12ca3 100644 --- a/alphastats/utils.py +++ b/alphastats/utils.py @@ -71,14 +71,17 @@ def inner(*args, **kwargs): return inner + def list_to_tuple(function): """ list are not hashable not suitable for caching convert to tuple """ + def wrapper(*args): args = [tuple(x) if type(x) == list else x for x in args] result = function(*args) result = tuple(result) if type(result) == list else result return result - return wrapper \ No newline at end of file + + return wrapper diff --git a/release/pyinstaller/alphastats_pyinstaller.py b/release/pyinstaller/alphastats_pyinstaller.py index 97b69c42..00163c24 100644 --- a/release/pyinstaller/alphastats_pyinstaller.py +++ b/release/pyinstaller/alphastats_pyinstaller.py @@ -2,11 +2,11 @@ try: import alphastats import multiprocessing + multiprocessing.freeze_support() - + except ModuleNotFoundError: pass from alphastats.gui import run - run() - + run() diff --git a/setup.py b/setup.py index 513c4936..8257c653 100644 --- a/setup.py +++ b/setup.py @@ -16,10 +16,10 @@ def get_long_description(): def get_requirements(): - with open('requirements.txt') as f: + with open("requirements.txt") as f: required = f.read().splitlines() return required - + def create_pip_wheel(): requirements = get_requirements() @@ -56,16 +56,16 @@ def create_pip_wheel(): "Topic :: Scientific/Engineering :: Bio-Informatics", ], packages=[ - "alphastats", - "alphastats.plots", + "alphastats", + "alphastats.plots", "alphastats.multicova", - "alphastats.gui", - "alphastats.data", + "alphastats.gui", + "alphastats.data", "alphastats.gui.pages", "alphastats.gui", "alphastats.gui.sample_data", "alphastats.gui.utils", - "alphastats.loader" + "alphastats.loader", ], include_package_data=True, entry_points={"console_scripts": "alphastats=alphastats.gui.gui:run",}, diff --git a/tests/test_DataSet.py b/tests/test_DataSet.py index d0319214..f67087c0 100644 --- a/tests/test_DataSet.py +++ b/tests/test_DataSet.py @@ -17,6 +17,7 @@ import os import copy import dictdiffer + # from pandas.api.types import is_object_dtype, is_numeric_dtype, is_bool_dtype from alphastats.loader.BaseLoader import BaseLoader @@ -184,10 +185,10 @@ def test_plot_sampledistribution(self): self.assertEqual(len(plot_dict.get("data")), 1) #  check if it is logscale self.assertEqual(plot_dict.get("layout").get("yaxis").get("type"), "log") - + def test_reset_preprocessing(self): self.assertEqual(self.obj.mat.shape, self.matrix_dim) - + self.obj.preprocess(remove_contaminations=True) self.assertEqual(self.obj.mat.shape, self.matrix_dim_filtered) @@ -257,7 +258,7 @@ def test_preprocess_remove_samples(self): def test_preprocess_normalize_zscore(self): self.obj.mat = pd.DataFrame({"a": [2, 5, 4], "b": [5, 4, 4], "c": [0, 10, 8]}) # zscore Normalization - self.obj.preprocess(log2_transform=False,normalization="zscore") + self.obj.preprocess(log2_transform=False, normalization="zscore") expected_mat = pd.DataFrame( { "a": [-1.33630621, 1.06904497, 0.26726124], @@ -270,7 +271,7 @@ def test_preprocess_normalize_zscore(self): def test_preprocess_normalize_quantile(self): self.obj.mat = pd.DataFrame({"a": [2, 5, 4], "b": [5, 4, 4], "c": [0, 10, 8]}) # Quantile Normalization - self.obj.preprocess(log2_transform=False,normalization="quantile") + self.obj.preprocess(log2_transform=False, normalization="quantile") expected_mat = pd.DataFrame( {"a": [0.0, 1.0, 0.5], "b": [1.0, 0.0, 0.0], "c": [0.0, 1.0, 0.5]} ) @@ -279,7 +280,7 @@ def test_preprocess_normalize_quantile(self): def test_preprocess_normalize_linear(self): self.obj.mat = pd.DataFrame({"a": [2, 5, 4], "b": [5, 4, 4], "c": [0, 10, 8]}) # Linear Normalization - self.obj.preprocess(log2_transform=False,normalization="linear") + self.obj.preprocess(log2_transform=False, normalization="linear") expected_mat = pd.DataFrame( { "a": [0.37139068, 0.42107596, 0.40824829], @@ -292,7 +293,7 @@ def test_preprocess_normalize_linear(self): def test_preprocess_normalize_vst(self): self.obj.mat = pd.DataFrame({"a": [2, 5, 4], "b": [5, 4, 4], "c": [0, 10, 8]}) # Linear Normalization - self.obj.preprocess(log2_transform=False,normalization="vst") + self.obj.preprocess(log2_transform=False, normalization="vst") expected_mat = pd.DataFrame( { "a": [-1.30773413, 1.12010046, 0.18763367], @@ -306,7 +307,7 @@ def test_preprocess_imputation_mean_values(self): self.obj.mat = pd.DataFrame( {"a": [2, np.nan, 4], "b": [5, 4, 4], "c": [np.nan, 10, np.nan]} ) - self.obj.preprocess(log2_transform=False,imputation="mean") + self.obj.preprocess(log2_transform=False, imputation="mean") expected_mat = pd.DataFrame( {"a": [2.0, 3.0, 4.0], "b": [5.0, 4.0, 4.0], "c": [10.0, 10.0, 10.0]} ) @@ -316,7 +317,7 @@ def test_preprocess_imputation_median_values(self): self.obj.mat = pd.DataFrame( {"a": [2, np.nan, 4], "b": [5, 4, 4], "c": [np.nan, 10, np.nan]} ) - self.obj.preprocess(log2_transform=False,imputation="median") + self.obj.preprocess(log2_transform=False, imputation="median") expected_mat = pd.DataFrame( {"a": [2.0, 3.0, 4.0], "b": [5.0, 4.0, 4.0], "c": [10.0, 10.0, 10.0]} ) @@ -326,7 +327,7 @@ def test_preprocess_imputation_knn_values(self): self.obj.mat = pd.DataFrame( {"a": [2, np.nan, 4], "b": [5, 4, 4], "c": [np.nan, 10, np.nan]} ) - self.obj.preprocess(log2_transform=False,imputation="knn") + self.obj.preprocess(log2_transform=False, imputation="knn") expected_mat = pd.DataFrame( {"a": [2.0, 3.0, 4.0], "b": [5.0, 4.0, 4.0], "c": [10.0, 10.0, 10.0]} ) @@ -336,7 +337,7 @@ def test_preprocess_imputation_randomforest_values(self): self.obj.mat = pd.DataFrame( {"a": [2, np.nan, 4], "b": [5, 4, 4], "c": [np.nan, 10, np.nan]} ) - self.obj.preprocess(log2_transform=False,imputation="randomforest") + self.obj.preprocess(log2_transform=False, imputation="randomforest") expected_mat = pd.DataFrame( { "a": [2.00000000e00, -9.22337204e12, 4.00000000e00], @@ -404,12 +405,10 @@ def test_load_evidence_wrong_sample_names(self): with self.assertRaises(ValueError): loader = MaxQuantLoader( file="testfiles/maxquant/proteinGroups.txt", - evidence_file="testfiles/maxquant_go/evidence.txt" + evidence_file="testfiles/maxquant_go/evidence.txt", ) DataSet( - loader=loader, - metadata_path=self.metadata_path, - sample_column="sample", + loader=loader, metadata_path=self.metadata_path, sample_column="sample", ) def test_plot_pca_group(self): @@ -448,15 +447,15 @@ def test_plot_volcano_with_grouplist_wrong_names(self): group1=["wrong_sample_name", "1_42_D9", "1_57_E8"], group2=["1_71_F10", "1_73_F12"], ) - + def test_plot_volcano_compare_preprocessing_modes(self): result_list = self.obj.plot_volcano( method="ttest", group1=["1_31_C6", "1_32_C7", "1_57_E8"], group2=["1_71_F10", "1_73_F12"], - compare_preprocessing_modes=True + compare_preprocessing_modes=True, ) - self.assertEqual(len(result_list), 9) + self.assertEqual(len(result_list), 9) def test_preprocess_subset(self): self.obj.preprocess(subset=True, log2_transform=False) @@ -505,9 +504,7 @@ def test_anova_with_tukey(self): def test_tukey_test(self): protein_id = "K7ERI9;A0A024R0T8;P02654;K7EJI9;K7ELM9;K7EPF9;K7EKP1" - tukey_df = self.obj.tukey_test( - protein_id=protein_id, group="disease", df=None - ) + tukey_df = self.obj.tukey_test(protein_id=protein_id, group="disease", df=None) self.assertEqual(tukey_df["p-tukey"][0], 0.674989009816342) def test_ancova(self): @@ -538,21 +535,26 @@ def test_plot_volcano_wald(self): Volcano Plot with wald test and list of samples """ self.obj.preprocess(imputation="knn") - self.obj.plot_volcano(group1 = ["1_31_C6", "1_32_C7", "1_33_C8"], - group2 = ["1_78_G5", "1_77_G4", "1_76_G3"], method="ttest") + self.obj.plot_volcano( + group1=["1_31_C6", "1_32_C7", "1_33_C8"], + group2=["1_78_G5", "1_77_G4", "1_76_G3"], + method="ttest", + ) column_added = "_comparison_column" in self.obj.metadata.columns.to_list() - self.assertTrue(column_added) + self.assertTrue(column_added) def test_plot_volcano_sam(self): - self.obj.preprocess(log2_transform=False, imputation="knn", normalization="zscore") + self.obj.preprocess( + log2_transform=False, imputation="knn", normalization="zscore" + ) plot = self.obj.plot_volcano( - column = "disease", - group1="type 2 diabetes mellitus", - group2 ="type 2 diabetes mellitus|non-alcoholic fatty liver disease", + column="disease", + group1="type 2 diabetes mellitus", + group2="type 2 diabetes mellitus|non-alcoholic fatty liver disease", method="sam", - draw_line =True, - perm= 10 + draw_line=True, + perm=10, ) # fdr lines get drawn @@ -562,9 +564,9 @@ def test_plot_volcano_sam(self): self.assertEqual(line_1, "spline") self.assertEqual(line_2, "spline") - def test_plot_clustermap_significant(self): import sys + sys.setrecursionlimit(100000) self.obj.preprocess(imputation="knn") plot = self.obj.plot_clustermap( @@ -609,63 +611,91 @@ def test_diff_expression_analysis_nocolumn(self): def test_diff_expression_analysis_list(self): self.obj.diff_expression_analysis( - group1 = ["1_31_C6", "1_32_C7", "1_33_C8"], - group2 = ["1_78_G5", "1_77_G4", "1_76_G3"], method="ttest") + group1=["1_31_C6", "1_32_C7", "1_33_C8"], + group2=["1_78_G5", "1_77_G4", "1_76_G3"], + method="ttest", + ) column_added = "_comparison_column" in self.obj.metadata.columns.to_list() - self.assertTrue(column_added) + self.assertTrue(column_added) def test_plot_intensity_non_sign(self): """ No significant label is added to intensity plot """ - plot = self.obj.plot_intensity(protein_id="S6BAR0", - group="disease", + plot = self.obj.plot_intensity( + protein_id="S6BAR0", + group="disease", subgroups=["liver cirrhosis", "healthy"], - add_significance=True) + add_significance=True, + ) - annotation = plot.to_plotly_json().get("layout").get("annotations")[1].get("text") + annotation = ( + plot.to_plotly_json().get("layout").get("annotations")[1].get("text") + ) self.assertEqual(annotation, "-") def test_plot_intensity_sign(self): """ Significant label * is added to intensity plot """ - plot = self.obj.plot_intensity(protein_id="Q9UL94", - group="disease", + plot = self.obj.plot_intensity( + protein_id="Q9UL94", + group="disease", subgroups=["liver cirrhosis", "healthy"], - add_significance=True) + add_significance=True, + ) - annotation = plot.to_plotly_json().get("layout").get("annotations")[1].get("text") + annotation = ( + plot.to_plotly_json().get("layout").get("annotations")[1].get("text") + ) self.assertEqual(annotation, "*") def test_plot_intensity_sign_01(self): """ Significant label ** is added to intensity plot """ - plot = self.obj.plot_intensity(protein_id="Q96JD0;Q96JD1;P01721", - group="disease", + plot = self.obj.plot_intensity( + protein_id="Q96JD0;Q96JD1;P01721", + group="disease", subgroups=["liver cirrhosis", "healthy"], - add_significance=True) + add_significance=True, + ) - annotation = plot.to_plotly_json().get("layout").get("annotations")[1].get("text") + annotation = ( + plot.to_plotly_json().get("layout").get("annotations")[1].get("text") + ) self.assertEqual(annotation, "**") def test_plot_intensity_sign_001(self): """ Highly significant label is added to intensity plot """ - plot = self.obj.plot_intensity(protein_id="Q9BWP8", - group="disease", + plot = self.obj.plot_intensity( + protein_id="Q9BWP8", + group="disease", subgroups=["liver cirrhosis", "healthy"], - add_significance=True) + add_significance=True, + ) - annotation = plot.to_plotly_json().get("layout").get("annotations")[1].get("text") + annotation = ( + plot.to_plotly_json().get("layout").get("annotations")[1].get("text") + ) self.assertEqual(annotation, "***") + def test_multicova_analysis(self): + results = self.obj.multi_covariat_analysis( + covariates=["disease", "Alkaline phosphatase measurement (88810008)"], + subset={"disease": ["healthy", "liver cirrhosis"]}, + ) + pass + + def test_multicova_analysis_invalid_covariates(self): + pass + # def test_perform_gsea(self): - # df = self.obj.perform_gsea(column="disease", - # group1="healthy", + # df = self.obj.perform_gsea(column="disease", + # group1="healthy", # group2="liver cirrhosis", # gene_sets= 'KEGG_2019_Human') @@ -806,26 +836,30 @@ def setUp(self): class TestSpectronautDataSet(BaseTestDataSet.BaseTest): @classmethod def setUpClass(cls): - + if os.path.isfile("testfiles/spectronaut/results.tsv") == False: - shutil.unpack_archive("testfiles/spectronaut/results.tsv.zip", "testfiles/spectronaut/") - - cls.cls_loader = SpectronautLoader(file="testfiles/spectronaut/results.tsv", filter_qvalue=False) + shutil.unpack_archive( + "testfiles/spectronaut/results.tsv.zip", "testfiles/spectronaut/" + ) + + cls.cls_loader = SpectronautLoader( + file="testfiles/spectronaut/results.tsv", filter_qvalue=False + ) cls.cls_metadata_path = "testfiles/spectronaut/metadata.xlsx" cls.cls_obj = DataSet( loader=cls.cls_loader, metadata_path=cls.cls_metadata_path, - sample_column="sample" + sample_column="sample", ) def setUp(self): self.loader = copy.deepcopy(self.cls_loader) self.metadata_path = copy.deepcopy(self.cls_metadata_path) self.obj = copy.deepcopy(self.cls_obj) - self.matrix_dim = (9,2458) + self.matrix_dim = (9, 2458) self.matrix_dim_filtered = (9, 2453) self.comparison_column = "condition" - + @classmethod def tearDownClass(cls): if os.path.isdir("testfiles/spectronaut/__MACOSX"): @@ -834,6 +868,5 @@ def tearDownClass(cls): os.remove("testfiles/spectronaut/results.tsv") - if __name__ == "__main__": unittest.main() diff --git a/tests/test_DataSet_Pathway.py b/tests/test_DataSet_Pathway.py index 69972250..9cfdfee0 100644 --- a/tests/test_DataSet_Pathway.py +++ b/tests/test_DataSet_Pathway.py @@ -52,12 +52,15 @@ def test_raise_error_no_evidence(self): def test_go_abundance_correction_with_list(self): df = self.obj.go_abundance_correction( - bg_sample=self.bg_sample, fg_protein_list=self.obj.mat.columns.to_list()[200:300] + bg_sample=self.bg_sample, + fg_protein_list=self.obj.mat.columns.to_list()[200:300], ) self.assertTrue(df.empty) def test_go_genome_list(self): - df = self.obj.go_genome(protein_list=self.obj.mat.columns.to_list()[600:700]) + df = self.obj.go_genome( + protein_list=self.obj.mat.columns.to_list()[600:700] + ) self.assertFalse(df.empty) def test_go_genome_sample(self): @@ -94,6 +97,5 @@ def setUp(self): self.bg_sample = "UT822" - if __name__ == "__main__": unittest.main() diff --git a/tests/test_loaders.py b/tests/test_loaders.py index 5476430e..71d91eff 100644 --- a/tests/test_loaders.py +++ b/tests/test_loaders.py @@ -132,6 +132,7 @@ def test_set_filter_columns_to_true_false(self): self.assertEqual(self.obj.rawinput["Only identified by site"].dtype, "bool") self.assertEqual(self.obj.rawinput["Potential contaminant"].dtype, "bool") + class TestDIANNLoader(BaseTestLoader.BaseTest): @classmethod def setUpClass(cls): @@ -190,46 +191,58 @@ def setUpClass(cls): cls.obj = FragPipeLoader(file="testfiles/fragpipe/combined_proteins.tsv") cls.df_dim = (10, 37) + class TestSpectronautLoader(BaseTestLoader.BaseTest): @classmethod def setUpClass(cls): - + if os.path.isfile("testfiles/spectronaut/results.tsv") == False: - shutil.unpack_archive("testfiles/spectronaut/results.tsv.zip", "testfiles/spectronaut/") - - cls.obj = SpectronautLoader(file="testfiles/spectronaut/results.tsv", filter_qvalue=False) + shutil.unpack_archive( + "testfiles/spectronaut/results.tsv.zip", "testfiles/spectronaut/" + ) + + cls.obj = SpectronautLoader( + file="testfiles/spectronaut/results.tsv", filter_qvalue=False + ) cls.df_dim = (2458, 11) def test_reading_non_european_comma(self): """ files with non european comma get read correctly """ - s = SpectronautLoader(file="testfiles/spectronaut/results_non_european_comma.tsv", filter_qvalue=False) - mean = s.rawinput["20221015_EV_TP_40SPD_LITDIA_MS1_Rapid_MS2_Rapid_57w_100ng_03_PG.Quantity"].mean() + s = SpectronautLoader( + file="testfiles/spectronaut/results_non_european_comma.tsv", + filter_qvalue=False, + ) + mean = s.rawinput[ + "20221015_EV_TP_40SPD_LITDIA_MS1_Rapid_MS2_Rapid_57w_100ng_03_PG.Quantity" + ].mean() def test_qvalue_filtering(self): - obj = SpectronautLoader(file="testfiles/spectronaut/results.tsv", filter_qvalue=True, qvalue_cutoff=0.00000001) + obj = SpectronautLoader( + file="testfiles/spectronaut/results.tsv", + filter_qvalue=True, + qvalue_cutoff=0.00000001, + ) self.assertEqual(obj.rawinput.shape, (2071, 10)) def test_qvalue_filtering_warning(self): with self.assertWarns(Warning): df = pd.read_csv("testfiles/spectronaut/results.tsv", sep="\t", decimal=",") - df.drop(columns = ["EG.Qvalue"], axis=1) + df.drop(columns=["EG.Qvalue"], axis=1) SpectronautLoader(file=df) def test_gene_name_column(self): df = pd.read_csv("testfiles/spectronaut/results.tsv", sep="\t", decimal=",") df["PG.Genes"] = 0 s = SpectronautLoader(file=df, filter_qvalue=False) - + @classmethod def tearDownClass(cls): if os.path.isdir("testfiles/spectronaut/__MACOSX"): shutil.rmtree("testfiles/spectronaut/__MACOSX") os.remove("testfiles/spectronaut/results.tsv") - - if __name__ == "__main__": From 9fee28e417bce3c294458ddd8a0c079af0bdccb0 Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Tue, 16 May 2023 16:55:41 +0200 Subject: [PATCH 04/17] ENH download metadata file in the gui --- HISTORY.md | 3 +++ alphastats/DataSet_Statistics.py | 2 -- alphastats/gui/pages/02_Import Data.py | 31 +++++++++++++--------- alphastats/statistics/MultiCovaAnalysis.py | 2 +- requirements.txt | 11 ++++---- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 96f84ec5..f92401bd 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,8 @@ # Changelog +# 0.6.0 +* ENH download metadata template in the GUI + # 0.5.4 * FIX altair version - binning of streamlit version diff --git a/alphastats/DataSet_Statistics.py b/alphastats/DataSet_Statistics.py index 73b02cce..4663d5f7 100644 --- a/alphastats/DataSet_Statistics.py +++ b/alphastats/DataSet_Statistics.py @@ -10,8 +10,6 @@ from typing import Union from alphastats.statistics.MultiCovaAnalysis import MultiCovaAnalysis - - from alphastats.statistics.DifferentialExpressionAnalysis import DifferentialExpressionAnalysis from alphastats.statistics.Anova import Anova diff --git a/alphastats/gui/pages/02_Import Data.py b/alphastats/gui/pages/02_Import Data.py index 924a9a56..4485fe94 100644 --- a/alphastats/gui/pages/02_Import Data.py +++ b/alphastats/gui/pages/02_Import Data.py @@ -1,6 +1,7 @@ import streamlit as st import sys import os +import io try: from alphastats.gui.utils.ui_helper import sidebar_info @@ -186,16 +187,20 @@ def create_metadata_file(): dataset = DataSet(loader=st.session_state.loader) st.session_state["metadata_columns"] = ["sample"] metadata = dataset.metadata - - if st.button("Add Column"): - st.write("xxx") - column_name = st.text_input("Column name", "") - metadata[column_name] = None - - metadata = st.experimental_data_editor(metadata, num_rows="fixed") - - # st.session_state.loader - + buffer = io.BytesIO() + + with pd.ExcelWriter(buffer, engine='xlsxwriter') as writer: + # Write each dataframe to a different worksheet. + metadata.to_excel(writer, sheet_name='Sheet1', index=False) + # Close the Pandas Excel writer and output the Excel file to the buffer + writer.close() + + st.download_button( + label="Download metadata template as Excel", + data=buffer, + file_name='metadata.xlsx', + mime='application/vnd.ms-excel' + ) def upload_metadatafile(software): @@ -229,8 +234,10 @@ def upload_metadatafile(software): display_loaded_dataset() - if st.button("Create metadata file"): - create_metadata_file() + create_metadata_file() + st.write("Download the template file and add additional information as columns to your samples such as disease group. " + + "Upload the updated metadata file.") + if st.button("Create a DataSet without metadata"): st.session_state["dataset"] = DataSet(loader=st.session_state.loader) diff --git a/alphastats/statistics/MultiCovaAnalysis.py b/alphastats/statistics/MultiCovaAnalysis.py index 14c71d85..88c5f744 100644 --- a/alphastats/statistics/MultiCovaAnalysis.py +++ b/alphastats/statistics/MultiCovaAnalysis.py @@ -2,7 +2,7 @@ import scipy import tqdm import pandas as pd -from statistics.StatisticUtils import StatisticUtils +from alphastats.statistics.StatisticUtils import StatisticUtils class MultiCovaAnalysis(StatisticUtils): def __init__(self, dataset, covariates: list, n_permutations: int=3, diff --git a/requirements.txt b/requirements.txt index 06f043bb..b00023bf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,9 @@ -pandas==2.0.0 +pandas==2.0.1 scikit-learn==1.2.1 data_cache>=0.1.6 -plotly==5.11.0 -statsmodels==0.13.5 -openpyxl>=3.0.10 +plotly==5.14.1 +statsmodels==0.14.0 +openpyxl>=3.1.2 sklearn_pandas==2.2.0 pingouin==0.5.3 scipy==1.10.1 @@ -19,4 +19,5 @@ numba-stats==0.5.0 swifter==1.2.0 click==8.0.1 kaleido==0.2.1 -combat==0.3.3 \ No newline at end of file +combat==0.3.3 +xlsxwriter==3.1.0 \ No newline at end of file From 07ef19ccce7fd74e55ca7c0053be34f6d955b260 Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Tue, 16 May 2023 17:51:16 +0200 Subject: [PATCH 05/17] multicova convert str to binary --- alphastats/DataSet_Statistics.py | 4 +-- alphastats/statistics/MultiCovaAnalysis.py | 31 ++++++++++++++++++---- tests/test_DataSet.py | 5 +--- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/alphastats/DataSet_Statistics.py b/alphastats/DataSet_Statistics.py index 4663d5f7..db0194b3 100644 --- a/alphastats/DataSet_Statistics.py +++ b/alphastats/DataSet_Statistics.py @@ -197,7 +197,7 @@ def multi_covariat_analysis( s0: float = 0.05, subset: dict = None, ) -> pd.DataFrame: - """_summary_ + """Perform Multicovariat Analysis Args: covariates (list): list of covariates, column names in metadata @@ -207,7 +207,7 @@ def multi_covariat_analysis( subset (dict, optional): _description_. Defaults to None. Returns: - pd.DataFrame: _description_ + pd.DataFrame: Multicova Analysis results """ res = MultiCovaAnalysis( diff --git a/alphastats/statistics/MultiCovaAnalysis.py b/alphastats/statistics/MultiCovaAnalysis.py index 88c5f744..ab0abb57 100644 --- a/alphastats/statistics/MultiCovaAnalysis.py +++ b/alphastats/statistics/MultiCovaAnalysis.py @@ -2,6 +2,7 @@ import scipy import tqdm import pandas as pd +import numpy as np from alphastats.statistics.StatisticUtils import StatisticUtils class MultiCovaAnalysis(StatisticUtils): @@ -18,33 +19,53 @@ def __init__(self, dataset, covariates: list, n_permutations: int=3, self._subset_metadata() self._check_covariat_input() self._check_na_values() + self._convert_string_to_binary() self._prepare_matrix() def _subset_metadata(self): + columns_to_keep = self.covariates + [self.dataset.sample] if self.subset is not None: # dict structure {"column_name": ["group1", "group2"]} subset_column = list(self.subset.keys())[0] groups = self.subset.get(subset_column) - self.metadata = self.dataset.metadata[self.dataset.metadata[subset_column].isin(groups)] + self.metadata = self.dataset.metadata[self.dataset.metadata[subset_column].isin(groups)][columns_to_keep] else: - self.metadata = self.dataset.metadata + self.metadata = self.dataset.metadata[columns_to_keep] def _check_covariat_input(self): # check whether covariates in metadata column misc_covariates = list(set(self.metadata.columns.to_list()) - set(self.covariates)) if len(misc_covariates)> 0: Warning(f"Covariates: {misc_covariates} are not found in Metadata.") - self.covariates = filter(lambda i: i not in misc_covariates, self.covariates) + self.covariates = [x for x in self.covariates if x not in misc_covariates] def _check_na_values(self): for covariate in self.covariates: - if self._prepare_matrixmetadata[covariate].isna().any(): + if self.dataset.metadata[covariate].isna().any(): self.covariates.remove(covariate) - Warning(f"Covariate: {covariate} contains missing values" + f"in metadata and will not be used for analysis.") + + def _convert_string_to_binary(self): + string_cols = self.metadata.select_dtypes(include=[object]).columns.to_list() + + if len(string_cols) > 0: + for col in string_cols: + col_values = list(set(self.metadata[col].to_list())) + + if len(col_values) == 2: + self.metadata[col] = np.where(self.metadata[col] == col_values[0], 0, 1) + + else: + if len(col_values) < 2: + col_values.append("example") + + subset_prompt = "¨subset={" + col + ":[" + col_values[0] + ","+ col_values[1]+"]}" + Warning(f"Covariate: {col} contains not exactly 2 binary values, instead {col_values}. " + f"Specify the values of the covariates you want to use for your analysis as: {subset_prompt} ") + def _prepare_matrix(self): transposed = self.dataset.mat.transpose() diff --git a/tests/test_DataSet.py b/tests/test_DataSet.py index 8f0893ae..b3443cb6 100644 --- a/tests/test_DataSet.py +++ b/tests/test_DataSet.py @@ -703,10 +703,7 @@ def test_batch_correction(self): self.obj.preprocess(subset=True, imputation="knn", normalization="quantile") self.obj.batch_correction(batch="batch_artifical_added") first_value = self.obj.mat.values[0,0] - self.assertAlmostEqual(0.0111, first_value, places=2) - - - + self.assertAlmostEqual(0.0111, first_value, places=2) def test_multicova_analysis(self): results = self.obj.multi_covariat_analysis( From bdb948cfd869202f6ce208a599d5d6d6f22b85e0 Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Wed, 17 May 2023 13:41:36 +0200 Subject: [PATCH 06/17] plot volcano --- HISTORY.md | 1 + alphastats/DataSet_Statistics.py | 2 +- alphastats/plots/VolcanoPlot.py | 2 +- alphastats/statistics/MultiCovaAnalysis.py | 32 ++++++++++++++++++++-- alphastats/statistics/StatisticUtils.py | 2 ++ tests/test_DataSet.py | 6 ++-- 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index f92401bd..d0cca991 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,7 @@ # 0.6.0 * ENH download metadata template in the GUI +* ENH multicova analysis # 0.5.4 * FIX altair version - binning of streamlit version diff --git a/alphastats/DataSet_Statistics.py b/alphastats/DataSet_Statistics.py index db0194b3..eddc6902 100644 --- a/alphastats/DataSet_Statistics.py +++ b/alphastats/DataSet_Statistics.py @@ -189,7 +189,7 @@ def ancova(self, protein_id:str, covar: Union[str, list], between:str) -> pd.Dat ancova_df = pingouin.ancova(df, dv=protein_id, covar=covar, between=between) return ancova_df - def multi_covariat_analysis( + def multicova_analysis( self, covariates: list, n_permutations: int = 3, diff --git a/alphastats/plots/VolcanoPlot.py b/alphastats/plots/VolcanoPlot.py index 5b72083e..a75b3ad4 100644 --- a/alphastats/plots/VolcanoPlot.py +++ b/alphastats/plots/VolcanoPlot.py @@ -95,7 +95,7 @@ def _perform_differential_expression_analysis(self): else: raise ValueError( f"{self.method} is not available." - + "Please select from 'ttest', 'sam' or 'anova' for anova with follow up tukey or 'wald' for wald-test." + + "Please select from 'ttest', 'sam', 'paired-ttest' or 'anova' for anova with follow up tukey or 'wald' for wald-test." ) @lru_cache(maxsize=20) diff --git a/alphastats/statistics/MultiCovaAnalysis.py b/alphastats/statistics/MultiCovaAnalysis.py index ab0abb57..c7e7349e 100644 --- a/alphastats/statistics/MultiCovaAnalysis.py +++ b/alphastats/statistics/MultiCovaAnalysis.py @@ -3,11 +3,12 @@ import tqdm import pandas as pd import numpy as np +import plotly.express as px from alphastats.statistics.StatisticUtils import StatisticUtils class MultiCovaAnalysis(StatisticUtils): def __init__(self, dataset, covariates: list, n_permutations: int=3, - fdr: float=0.05, s0: float=0.05, subset: dict=None): + fdr: float=0.05, s0: float=0.05, subset: dict=None, plot:bool=False): self.dataset = dataset self.covariates = covariates @@ -15,6 +16,7 @@ def __init__(self, dataset, covariates: list, n_permutations: int=3, self.fdr = fdr self.s0 = s0 self.subset = subset + self.plot = plot self._subset_metadata() self._check_covariat_input() @@ -65,13 +67,29 @@ def _convert_string_to_binary(self): subset_prompt = "¨subset={" + col + ":[" + col_values[0] + ","+ col_values[1]+"]}" Warning(f"Covariate: {col} contains not exactly 2 binary values, instead {col_values}. " f"Specify the values of the covariates you want to use for your analysis as: {subset_prompt} ") - + self.covariates.remove(col) def _prepare_matrix(self): transposed = self.dataset.mat.transpose() transposed[self.dataset.index_column] = transposed.index transposed = transposed.reset_index(drop=True) self.transposed = transposed[self.metadata[self.dataset.sample].to_list()] + + def _plot_volcano_regression(self, res_real, variable): + + sig_col = res_real.filter(regex=variable+"_"+"FDR").columns[0] + sig_level = sig_col.replace("_", " ") + + fig = px.scatter(x=res_real[variable+"_"+"fc"], + y=-np.log10(res_real[variable+"_"+"pval"]), + color=res_real[sig_col], + color_discrete_map={'sig': '#009599', 'non_sig': '#404040'}, + hover_name=res_real[self.dataset.index_column], + title=variable, + labels=dict(x="beta value", y="-log10(p-value)", color=sig_level)) + fig.show() + return fig + def calculate(self): from alphastats.multicova import multicova @@ -89,7 +107,15 @@ def calculate(self): fdr=self.fdr, s0=self.s0 ) - return res + res[self.dataset.index_column] = self.dataset.mat.columns.to_list() + plot_list = [] + + if self.plot: + for variable in self.covariates: + plot = self._plot_volcano_regression(res_real=res, variable=variable) + plot_list.append(plot) + + return res, plot_list diff --git a/alphastats/statistics/StatisticUtils.py b/alphastats/statistics/StatisticUtils.py index 5ec6b93a..f939e7e9 100644 --- a/alphastats/statistics/StatisticUtils.py +++ b/alphastats/statistics/StatisticUtils.py @@ -1,3 +1,5 @@ +import numpy as no + class StatisticUtils: def __init__(self) -> None: pass diff --git a/tests/test_DataSet.py b/tests/test_DataSet.py index b3443cb6..9397eb2f 100644 --- a/tests/test_DataSet.py +++ b/tests/test_DataSet.py @@ -706,11 +706,13 @@ def test_batch_correction(self): self.assertAlmostEqual(0.0111, first_value, places=2) def test_multicova_analysis(self): - results = self.obj.multi_covariat_analysis( + self.obj.preprocess(imputation="knn", normalization="zscore", subset=True) + res, plot_list = self.obj.multicova_analysis( covariates=["disease", "Alkaline phosphatase measurement (88810008)"], subset={"disease": ["healthy", "liver cirrhosis"]}, ) - pass + self.assertAlmostEqual(-0.2873, res['disease_fc'].iloc[1], places=2) + def test_multicova_analysis_invalid_covariates(self): pass From c6aa156e06c815eafa08404fb1cf9db5004a3c3c Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Wed, 17 May 2023 16:15:58 +0200 Subject: [PATCH 07/17] rename columns --- testfiles/maxquant/metadata.xlsx | Bin 27604 -> 27612 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/testfiles/maxquant/metadata.xlsx b/testfiles/maxquant/metadata.xlsx index deb28e7e8c59e6f7bba729f715cd62f88df67782..0c837faacfa0e8e50d38c9817cdecc4b1ca3b308 100644 GIT binary patch delta 18021 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

)`=B!LaR%u4Fk6F0fV)In45}EkUM>pQA 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 KfLMG#_ Date: Wed, 17 May 2023 16:51:54 +0200 Subject: [PATCH 08/17] fixes --- alphastats/DataSet_Statistics.py | 16 ++++++++++------ alphastats/statistics/MultiCovaAnalysis.py | 14 +++++++------- testfiles/maxquant/metadata.xlsx | Bin 27612 -> 27613 bytes tests/test_DataSet.py | 9 +++++++-- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/alphastats/DataSet_Statistics.py b/alphastats/DataSet_Statistics.py index eddc6902..bf3202f1 100644 --- a/alphastats/DataSet_Statistics.py +++ b/alphastats/DataSet_Statistics.py @@ -196,26 +196,30 @@ def multicova_analysis( fdr: float = 0.05, s0: float = 0.05, subset: dict = None, - ) -> pd.DataFrame: + ) -> Union[pd.DataFrame, list]: """Perform Multicovariat Analysis + will return a pandas DataFrame with the results and a list of volcano plots (for each covariat) Args: covariates (list): list of covariates, column names in metadata n_permutations (int, optional): number of permutations. Defaults to 3. fdr (float, optional): False Discovery Rate. Defaults to 0.05. - s0 (float, optional): _description_. Defaults to 0.05. - subset (dict, optional): _description_. Defaults to None. + s0 (float, optional): . Defaults to 0.05. + subset (dict, optional): for categorical covariates . Defaults to None. Returns: pd.DataFrame: Multicova Analysis results """ - - res = MultiCovaAnalysis( + + res, plot_list= MultiCovaAnalysis( dataset=self, covariates=covariates, n_permutations=n_permutations, fdr=fdr, s0=s0, subset=subset, + plot=True ).calculate() - return res + return res, plot_list + + \ No newline at end of file diff --git a/alphastats/statistics/MultiCovaAnalysis.py b/alphastats/statistics/MultiCovaAnalysis.py index c7e7349e..653bd747 100644 --- a/alphastats/statistics/MultiCovaAnalysis.py +++ b/alphastats/statistics/MultiCovaAnalysis.py @@ -5,6 +5,7 @@ import numpy as np import plotly.express as px from alphastats.statistics.StatisticUtils import StatisticUtils +import warnings class MultiCovaAnalysis(StatisticUtils): def __init__(self, dataset, covariates: list, n_permutations: int=3, @@ -18,8 +19,8 @@ def __init__(self, dataset, covariates: list, n_permutations: int=3, self.subset = subset self.plot = plot - self._subset_metadata() self._check_covariat_input() + self._subset_metadata() self._check_na_values() self._convert_string_to_binary() self._prepare_matrix() @@ -37,9 +38,9 @@ def _subset_metadata(self): def _check_covariat_input(self): # check whether covariates in metadata column - misc_covariates = list(set(self.metadata.columns.to_list()) - set(self.covariates)) + misc_covariates = list(set(self.covariates) - set(self.dataset.metadata.columns.to_list())) if len(misc_covariates)> 0: - Warning(f"Covariates: {misc_covariates} are not found in Metadata.") + warnings.warn(f"Covariates: {misc_covariates} are not found in Metadata.") self.covariates = [x for x in self.covariates if x not in misc_covariates] @@ -47,11 +48,11 @@ def _check_na_values(self): for covariate in self.covariates: if self.dataset.metadata[covariate].isna().any(): self.covariates.remove(covariate) - Warning(f"Covariate: {covariate} contains missing values" + + warnings.warn(f"Covariate: {covariate} contains missing values" + f"in metadata and will not be used for analysis.") def _convert_string_to_binary(self): - string_cols = self.metadata.select_dtypes(include=[object]).columns.to_list() + string_cols = self.metadata[self.covariates].select_dtypes(include=[object]).columns.to_list() if len(string_cols) > 0: for col in string_cols: @@ -65,7 +66,7 @@ def _convert_string_to_binary(self): col_values.append("example") subset_prompt = "¨subset={" + col + ":[" + col_values[0] + ","+ col_values[1]+"]}" - Warning(f"Covariate: {col} contains not exactly 2 binary values, instead {col_values}. " + warnings.warn(f"Covariate: {col} contains not exactly 2 binary values, instead {col_values}. " f"Specify the values of the covariates you want to use for your analysis as: {subset_prompt} ") self.covariates.remove(col) @@ -76,7 +77,6 @@ def _prepare_matrix(self): self.transposed = transposed[self.metadata[self.dataset.sample].to_list()] def _plot_volcano_regression(self, res_real, variable): - sig_col = res_real.filter(regex=variable+"_"+"FDR").columns[0] sig_level = sig_col.replace("_", " ") diff --git a/testfiles/maxquant/metadata.xlsx b/testfiles/maxquant/metadata.xlsx index 0c837faacfa0e8e50d38c9817cdecc4b1ca3b308..9dbdb1a4cf6bbed5d6e542d9a159a4eee8d37828 100644 GIT binary patch delta 15875 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 AaR2}S delta 15780 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 WeDw-^xj$ZZz*-w}Xeg^+L;nvo&8~?6 diff --git a/tests/test_DataSet.py b/tests/test_DataSet.py index 9397eb2f..a0d023bf 100644 --- a/tests/test_DataSet.py +++ b/tests/test_DataSet.py @@ -708,14 +708,19 @@ def test_batch_correction(self): def test_multicova_analysis(self): self.obj.preprocess(imputation="knn", normalization="zscore", subset=True) res, plot_list = self.obj.multicova_analysis( - covariates=["disease", "Alkaline phosphatase measurement (88810008)"], + covariates=["disease", "Alkaline phosphatase measurement"], subset={"disease": ["healthy", "liver cirrhosis"]}, ) self.assertAlmostEqual(-0.2873, res['disease_fc'].iloc[1], places=2) def test_multicova_analysis_invalid_covariates(self): - pass + self.obj.preprocess(imputation="knn", normalization="zscore", subset=True) + res, _ = self.obj.multicova_analysis( + covariates=["disease", "Alkaline phosphatase measurement", "Body mass index ", "not here"], + subset={"disease": ["healthy", "liver cirrhosis"]}, + ) + self.assertEqual(res.shape[1], 45) # def test_perform_gsea(self): # df = self.obj.perform_gsea(column="disease", From c059aa6a89733e46ed1f2229584ea1078ecd9d61 Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Wed, 17 May 2023 17:28:16 +0200 Subject: [PATCH 09/17] data completeness cut off --- HISTORY.md | 1 + alphastats/DataSet.py | 1 + alphastats/DataSet_Preprocess.py | 33 ++++++++++++++++++++++++ alphastats/gui/pages/03_Preprocessing.py | 6 +++++ alphastats/gui/utils/analysis_helper.py | 4 +++ tests/test_DataSet.py | 4 +++ 6 files changed, 49 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index d0cca991..ee514ebc 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,6 +3,7 @@ # 0.6.0 * ENH download metadata template in the GUI * ENH multicova analysis +* ENH filter data completeness `dataset.preprocess(data_completeness=0.7)` # 0.5.4 * FIX altair version - binning of streamlit version diff --git a/alphastats/DataSet.py b/alphastats/DataSet.py index 05d7d853..c83506f0 100644 --- a/alphastats/DataSet.py +++ b/alphastats/DataSet.py @@ -203,6 +203,7 @@ def _save_dataset_info(self): "Contaminations have been removed": False, "Contamination columns": self.filter_columns, "Number of removed ProteinGroups due to contaminaton": 0, + "Data completeness cut-off": 0, } return preprocessing_dict diff --git a/alphastats/DataSet_Preprocess.py b/alphastats/DataSet_Preprocess.py index 5efeea80..091421c9 100644 --- a/alphastats/DataSet_Preprocess.py +++ b/alphastats/DataSet_Preprocess.py @@ -29,6 +29,34 @@ def preprocess_print_info(self): """Print summary of preprocessing steps""" print(pd.DataFrame(self.preprocessing_info.items())) + def _remove_na_values(self, cut_off): + cut = 1 - cut_off + limit = self.mat.shape[0] * cut + + keep_list = list() + invalid = 0 + for column_name in self.mat.columns: + column = self.mat[column_name] + # Get the count of Zeros in column + count = (column == 0).sum() + try: + count = count.item() + if isinstance(count, int): + if count < limit: + keep_list += [column_name] + + except ValueError: + invalid +=1 + continue + + self.mat= self.mat[keep_list] + self.preprocessing_info.update( + {"Data completeness cut-off": cut_off} + ) + percentage = cut_off * 100 + print(f"Proteins with a data completeness across all samples of less than {percentage} % have been removed.") + + def _filter(self): if len(self.filter_columns) == 0: logging.info("No columns to filter.") @@ -221,6 +249,7 @@ def preprocess( log2_transform: bool=True, remove_contaminations: bool=False, subset: bool=False, + data_completeness: float=0, normalization: str=None, imputation: str=None, remove_samples: list=None, @@ -262,6 +291,7 @@ def preprocess( remove_contaminations (bool, optional): remove ProteinGroups that are identified as contamination. log2_transform (bool, optional): Log2 transform data. Default to True. normalization (str, optional): method to normalize data: either "zscore", "quantile", "linear". Defaults to None. + data_completeness (float, optional): data completeness across all samples between 0-1. Defaults to 0. remove_samples (list, optional): list with sample ids to remove. Defaults to None. imputation (str, optional): method to impute data: either "mean", "median", "knn" or "randomforest". Defaults to None. subset (bool, optional): filter matrix so only samples that are described in metadata found in matrix. Defaults to False. @@ -274,6 +304,9 @@ def preprocess( if subset: self.mat = self._subset() + + if data_completeness> 0: + self._remove_na_values(cut_off=data_completeness) if log2_transform: self._log2_transform() diff --git a/alphastats/gui/pages/03_Preprocessing.py b/alphastats/gui/pages/03_Preprocessing.py index 40ca2d44..04852a58 100644 --- a/alphastats/gui/pages/03_Preprocessing.py +++ b/alphastats/gui/pages/03_Preprocessing.py @@ -34,6 +34,11 @@ def preprocessing(): options=st.session_state.dataset.metadata[st.session_state.dataset.sample].to_list() ) + data_completeness = st.number_input( + f"Data completeness across samples cut-off \n(0.7 -> protein has to be detected in at least 70% of the samples)", + value=0, min_value=0, max_value=1 + ) + log2_transform = st.selectbox( "Log2-transform dataset", options=[True, False], ) @@ -56,6 +61,7 @@ def preprocessing(): remove_contaminations=remove_contaminations, log2_transform=log2_transform, remove_samples = remove_samples, + data_completeness=data_completeness, subset=subset, normalization=normalization, imputation=imputation, diff --git a/alphastats/gui/utils/analysis_helper.py b/alphastats/gui/utils/analysis_helper.py index e4aacf24..48220e31 100644 --- a/alphastats/gui/utils/analysis_helper.py +++ b/alphastats/gui/utils/analysis_helper.py @@ -356,3 +356,7 @@ def load_options(): st.session_state["plotting_options"] = plotting_options st.session_state["statistic_options"] = statistic_options + + +def gui_multicova_analysis(): + pass diff --git a/tests/test_DataSet.py b/tests/test_DataSet.py index a0d023bf..0af2a074 100644 --- a/tests/test_DataSet.py +++ b/tests/test_DataSet.py @@ -415,6 +415,10 @@ def test_plot_pca_group(self): pca_plot = self.obj.plot_pca(group=self.comparison_column) # 5 different disease self.assertEqual(len(pca_plot.to_plotly_json().get("data")), 5) + + def test_data_completeness(self): + self.obj.preprocess(log2_transform=False, data_completeness=0.7) + self.assertEqual(self.obj.mat.shape[1], 433) def test_plot_pca_circles(self): pca_plot = self.obj.plot_pca(group=self.comparison_column, circle=True) From 428f4fbca0f3346f93cce5f474cb19af0e3e2143 Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Fri, 19 May 2023 13:01:50 +0200 Subject: [PATCH 10/17] generic loader --- HISTORY.md | 1 + alphastats/DataSet.py | 7 ++++ alphastats/DataSet_Statistics.py | 1 + alphastats/gui/pages/02_Import Data.py | 52 +++++++++++++++++++------- alphastats/loader/BaseLoader.py | 8 ++-- alphastats/loader/FragPipeLoader.py | 13 ++++--- alphastats/loader/GenericLoader.py | 44 ++++++++++++++++++++++ alphastats/loader/MaxQuantLoader.py | 12 +++--- tests/test_DataSet.py | 40 ++++++++++++++++++++ 9 files changed, 148 insertions(+), 30 deletions(-) create mode 100644 alphastats/loader/GenericLoader.py diff --git a/HISTORY.md b/HISTORY.md index ee514ebc..ecd4c6a4 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,6 +4,7 @@ * ENH download metadata template in the GUI * ENH multicova analysis * ENH filter data completeness `dataset.preprocess(data_completeness=0.7)` +* ADD `GenericLoader` for not supported data formats # 0.5.4 * FIX altair version - binning of streamlit version diff --git a/alphastats/DataSet.py b/alphastats/DataSet.py index c83506f0..ac10966b 100644 --- a/alphastats/DataSet.py +++ b/alphastats/DataSet.py @@ -10,6 +10,7 @@ from alphastats.loader.FragPipeLoader import FragPipeLoader from alphastats.loader.MaxQuantLoader import MaxQuantLoader from alphastats.loader.SpectronautLoader import SpectronautLoader +from alphastats.loader.GenericLoader import GenericLoader from alphastats.DataSet_Plot import Plot from alphastats.DataSet_Preprocess import Preprocess @@ -69,6 +70,7 @@ def __init__(self, loader, metadata_path=None, sample_column=None): self.create_matrix() self._check_matrix_values() self.metadata = None + if metadata_path is not None: self.sample = sample_column self.load_metadata(file_path=metadata_path) @@ -76,6 +78,10 @@ def __init__(self, loader, metadata_path=None, sample_column=None): else: self._create_metadata() + + if self.loader == "Generic": + intensity_column = loader._extract_sample_names(metadata=self.metadata, sample_column=self.sample) + self.intensity_column = intensity_column # save preprocessing settings self.preprocessing_info = self._save_dataset_info() @@ -103,6 +109,7 @@ def _check_loader(self, loader): DIANNLoader, FragPipeLoader, SpectronautLoader, + GenericLoader ), ): raise LoaderError( diff --git a/alphastats/DataSet_Statistics.py b/alphastats/DataSet_Statistics.py index bf3202f1..7ec59114 100644 --- a/alphastats/DataSet_Statistics.py +++ b/alphastats/DataSet_Statistics.py @@ -189,6 +189,7 @@ def ancova(self, protein_id:str, covar: Union[str, list], between:str) -> pd.Dat ancova_df = pingouin.ancova(df, dv=protein_id, covar=covar, between=between) return ancova_df + @ignore_warning(RuntimeWarning) def multicova_analysis( self, covariates: list, diff --git a/alphastats/gui/pages/02_Import Data.py b/alphastats/gui/pages/02_Import Data.py index 4485fe94..0eaf098d 100644 --- a/alphastats/gui/pages/02_Import Data.py +++ b/alphastats/gui/pages/02_Import Data.py @@ -84,12 +84,17 @@ def check_software_file(df, software): def print_software_import_info(software): - import_file = software_options.get(software).get("import_file") - string_output = f"Please upload {import_file} file from {software}." + if software != "Other": + import_file = software_options.get(software).get("import_file") + string_output = f"Please upload {import_file} file from {software}." + + else: + string_output = f"Please upload your proteomics file." + return string_output -def select_columns_for_loaders(software): +def select_columns_for_loaders(software, software_df:None): """ select intensity and index column depending on software will be saved in session state @@ -98,19 +103,37 @@ def select_columns_for_loaders(software): st.markdown("### 2. Select columns used for further analysis.") st.markdown("Select intensity columns for further analysis") - st.selectbox( - "Intensity Column", - options=software_options.get(software).get("intensity_column"), - key="intensity_column", - ) + if software != "Other": + + st.selectbox( + "Intensity Column", + options=software_options.get(software).get("intensity_column"), + key="intensity_column", + ) - st.markdown("Select index column (with ProteinGroups) for further analysis") + st.markdown("Select index column (with ProteinGroups) for further analysis") + + st.selectbox( + "Index Column", + options=software_options.get(software).get("index_column"), + + key="index_column", + ) + else: + st.selectbox( + "Intensity Columns", + options=software_df.columns.to_list(), + key="intensity_column", + ) + + st.markdown("Select index column (with ProteinGroups) for further analysis") + + st.selectbox( + "Index Column", + options=software_df.columns.to_list(), + key="index_column", + ) - st.selectbox( - "Index Column", - options=software_options.get(software).get("index_column"), - key="index_column", - ) def load_proteomics_data(uploaded_file, intensity_column, index_column, software): @@ -296,6 +319,7 @@ def import_data(): "DIANN", "Fragpipe", "Spectronaut", + "Other", ], ) diff --git a/alphastats/loader/BaseLoader.py b/alphastats/loader/BaseLoader.py index a08571e1..581f6a3d 100644 --- a/alphastats/loader/BaseLoader.py +++ b/alphastats/loader/BaseLoader.py @@ -4,20 +4,20 @@ import numpy as np from alphastats.utils import find_duplicates_in_list import pkg_resources - +from typing import Union class BaseLoader: """Parent class of Loaders""" - def __init__(self, file, intensity_column, index_column, sep): - """BaseLoader for AlphaPept, MaxQuant, Fragpipe and DIANNLoader + def __init__(self, file:Union[str, pd.DataFrame], intensity_column:str, index_column:str, sep:str): + """BaseLoader for AlphaPept, MaxQuant, Fragpipe, Spectronau and DIANNLoader Args: file_path (str): path to file sep (str, optional): file separation. Defaults to "\t". """ - # self._check_if_file_exists(file=file) + if isinstance(file, pd.DataFrame): self.rawinput = file else: diff --git a/alphastats/loader/FragPipeLoader.py b/alphastats/loader/FragPipeLoader.py index cebd8391..18563c6c 100644 --- a/alphastats/loader/FragPipeLoader.py +++ b/alphastats/loader/FragPipeLoader.py @@ -1,5 +1,6 @@ from alphastats.loader.BaseLoader import BaseLoader import pandas as pd +from typing import Union # Philosopher # class name needs to be discussed whether MSFragger/Fragpipe/Philospher @@ -10,12 +11,12 @@ class FragPipeLoader(BaseLoader): def __init__( self, - file, - intensity_column="[sample] MaxLFQ Intensity ", - index_column="Protein", - gene_names_column="Gene Names", - confidence_column="Protein Probability", - sep="\t", + file:Union[str, pd.DataFrame], + intensity_column:str="[sample] MaxLFQ Intensity ", + index_column:str="Protein", + gene_names_column:str="Gene Names", + confidence_column:str="Protein Probability", + sep:str="\t", **kwargs ): diff --git a/alphastats/loader/GenericLoader.py b/alphastats/loader/GenericLoader.py new file mode 100644 index 00000000..30b17638 --- /dev/null +++ b/alphastats/loader/GenericLoader.py @@ -0,0 +1,44 @@ + +from alphastats.loader.BaseLoader import BaseLoader + +import pandas as pd +from typing import Union + +class GenericLoader(BaseLoader): + def __init__(self, file:Union[str, pd.DataFrame], intensity_column:list, index_column:str, sep:str): + """Generic Loader for you proteomics data + + Args: + file (Union[str, pd.DataFrame]): path to your proteomics file or pandas.DataFrame + intensity_column (list): list of samples with intensity + index_column (str): column with Protein IDs or Gene names, used for indexing + sep (str): file separation + """ + if isinstance(file, pd.DataFrame): + self.rawinput = file + else: + self.rawinput = pd.read_csv(file, sep=sep, low_memory=False) + self.intensity_column = "[sample]" + self.intensity_column_list = intensity_column + self.index_column = index_column + self.filter_columns = [] + self.confidence_column = None + self.software = "Generic" + self.evidence_df = None + self.gene_names = None + self.ptm_df = None + self._add_contamination_column() + self._check_if_columns_are_present() + self._read_all_columns_as_string() + + def _extract_sample_names(self, metadata:pd.DataFrame, sample_column:str): + sample_names = metadata[sample_column].to_list() + + for intensity_column in self.intensity_column_list: + for sample in sample_names: + if sample in intensity_column: + sample_structure = intensity_column.replace(sample, "[sample]") + + self.intensity_column = sample_structure + return sample_structure + diff --git a/alphastats/loader/MaxQuantLoader.py b/alphastats/loader/MaxQuantLoader.py index 1902391b..3897239b 100644 --- a/alphastats/loader/MaxQuantLoader.py +++ b/alphastats/loader/MaxQuantLoader.py @@ -9,13 +9,13 @@ class MaxQuantLoader(BaseLoader): def __init__( self, file, - intensity_column="LFQ intensity [sample]", - index_column="Protein IDs", - gene_names_column="Gene names", - filter_columns=["Only identified by site", "Reverse", "Potential contaminant"], - confidence_column="Q-value", + intensity_column:str="LFQ intensity [sample]", + index_column:str="Protein IDs", + gene_names_column:str="Gene names", + filter_columns:list=["Only identified by site", "Reverse", "Potential contaminant"], + confidence_column:str="Q-value", evidence_file=None, - sep="\t", + sep:str="\t", **kwargs ): """Loader MaxQuant output diff --git a/tests/test_DataSet.py b/tests/test_DataSet.py index 0af2a074..f8c9bd83 100644 --- a/tests/test_DataSet.py +++ b/tests/test_DataSet.py @@ -26,6 +26,7 @@ from alphastats.loader.AlphaPeptLoader import AlphaPeptLoader from alphastats.loader.FragPipeLoader import FragPipeLoader from alphastats.loader.SpectronautLoader import SpectronautLoader +from alphastats.loader.GenericLoader import GenericLoader from alphastats.DataSet import DataSet from alphastats.DataSet_Statistics import Statistics @@ -899,6 +900,45 @@ def tearDownClass(cls): shutil.rmtree("testfiles/spectronaut/__MACOSX") os.remove("testfiles/spectronaut/results.tsv") + +class TestGenericDataSet(BaseTestDataSet.BaseTest): + @classmethod + def setUpClass(cls): + if os.path.isfile("testfiles/fragpipe/combined_proteins.tsv") == False: + shutil.unpack_archive( + "testfiles/fragpipe/combined_proteins.tsv.zip", "testfiles/fragpipe" + ) + + cls.cls_loader = GenericLoader( + file="testfiles/fragpipe/combined_proteins.tsv", + intensity_column=[ + "S1 Razor Intensity", "S2 Razor Intensity", "S3 Razor Intensity", + "S4 Razor Intensity", "S5 Razor Intensity", "S6 Razor Intensity", + "S7 Razor Intensity", "S8 Razor Intensity" + ], + index_column="Protein", + ) + cls.cls_metadata_path = "testfiles/fragpipe/metadata.xlsx" + cls.cls_obj = DataSet( + loader=cls.cls_loader, + metadata_path=cls.cls_metadata_path, + sample_column="analytical_sample external_id", + ) + + def setUp(self): + self.loader = copy.deepcopy(self.cls_loader) + self.metadata_path = copy.deepcopy(self.cls_metadata_path) + self.obj = copy.deepcopy(self.cls_obj) + self.matrix_dim = (8, 6) + self.matrix_dim_filtered = (8, 6) + self.comparison_column = "grouping1" + + @classmethod + def tearDownClass(cls): + if os.path.isdir("testfiles/fragpipe/__MACOSX"): + shutil.rmtree("testfiles/fragpipe/__MACOSX") + + os.remove("testfiles/fragpipe/results.tsv") if __name__ == "__main__": From 272e851b42af861f4ac6e5911cac9201ef3444a1 Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Mon, 3 Jul 2023 10:12:13 +0200 Subject: [PATCH 11/17] fixs --- tests/test_DataSet.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_DataSet.py b/tests/test_DataSet.py index abe88ae3..6cafbf30 100644 --- a/tests/test_DataSet.py +++ b/tests/test_DataSet.py @@ -419,7 +419,7 @@ def test_plot_pca_group(self): def test_data_completeness(self): self.obj.preprocess(log2_transform=False, data_completeness=0.7) - self.assertEqual(self.obj.mat.shape[1], 433) + self.assertEqual(self.obj.mat.shape[1], 517) def test_plot_pca_circles(self): pca_plot = self.obj.plot_pca(group=self.comparison_column, circle=True) @@ -936,6 +936,7 @@ def setUpClass(cls): "S7 Razor Intensity", "S8 Razor Intensity" ], index_column="Protein", + sep="\t" ) cls.cls_metadata_path = "testfiles/fragpipe/metadata.xlsx" cls.cls_obj = DataSet( From ecb382ecc0cd86ba073a8f3e1ffd2e83c497daad Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Mon, 3 Jul 2023 10:23:10 +0200 Subject: [PATCH 12/17] fix --- tests/test_DataSet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_DataSet.py b/tests/test_DataSet.py index 6cafbf30..c77cb82b 100644 --- a/tests/test_DataSet.py +++ b/tests/test_DataSet.py @@ -735,7 +735,7 @@ def test_multicova_analysis(self): covariates=["disease", "Alkaline phosphatase measurement"], subset={"disease": ["healthy", "liver cirrhosis"]}, ) - self.assertAlmostEqual(-0.2873, res['disease_fc'].iloc[1], places=2) + self.assertAlmostEqual(0.3063, res['disease_fc'].iloc[1], places=2) def test_multicova_analysis_invalid_covariates(self): From f0780d2de38db70411346266cc9aa1ed06b2e244 Mon Sep 17 00:00:00 2001 From: elena-krismer Date: Mon, 3 Jul 2023 16:50:28 +0200 Subject: [PATCH 13/17] fix genericloader --- alphastats/DataSet.py | 16 +++--- alphastats/gui/pages/02_Import Data.py | 64 ++++++++---------------- alphastats/gui/utils/analysis_helper.py | 27 ++++++---- alphastats/gui/utils/software_options.py | 28 ++++++++--- alphastats/loader/BaseLoader.py | 2 +- alphastats/loader/GenericLoader.py | 23 +++++++-- alphastats/loader/MaxQuantLoader.py | 3 +- 7 files changed, 91 insertions(+), 72 deletions(-) diff --git a/alphastats/DataSet.py b/alphastats/DataSet.py index 24301e2b..73dd7885 100644 --- a/alphastats/DataSet.py +++ b/alphastats/DataSet.py @@ -154,14 +154,18 @@ def create_matrix(self): rows the samples. """ - regex_find_intensity_columns = self.intensity_column.replace("[sample]", ".*") - df = self.rawinput df = df.set_index(self.index_column) - df = df.filter(regex=(regex_find_intensity_columns), axis=1) - # remove Intensity so only sample names remain - substring_to_remove = regex_find_intensity_columns.replace(".*", "") - df.columns = df.columns.str.replace(substring_to_remove, "") + + if isinstance(self.intensity_column, str): + regex_find_intensity_columns = self.intensity_column.replace("[sample]", ".*") + df = df.filter(regex=(regex_find_intensity_columns), axis=1) + # remove Intensity so only sample names remain + substring_to_remove = regex_find_intensity_columns.replace(".*", "") + df.columns = df.columns.str.replace(substring_to_remove, "") + + else: + df = df[self.intensity_column] # transpose dataframe mat = df.transpose() mat.replace([np.inf, -np.inf], np.nan, inplace=True) diff --git a/alphastats/gui/pages/02_Import Data.py b/alphastats/gui/pages/02_Import Data.py index 0eaf098d..aaa07e11 100644 --- a/alphastats/gui/pages/02_Import Data.py +++ b/alphastats/gui/pages/02_Import Data.py @@ -31,6 +31,9 @@ user_session_id = session_id st.session_state["user_session_id"] = user_session_id +if "loader" not in st.session_state: + st.session_state["loader"] = None + def load_options(): @@ -82,18 +85,6 @@ def check_software_file(df, software): "https://fragpipe.nesvilab.org/docs/tutorial_fragpipe_outputs.html#combined_proteintsv" ) - -def print_software_import_info(software): - if software != "Other": - import_file = software_options.get(software).get("import_file") - string_output = f"Please upload {import_file} file from {software}." - - else: - string_output = f"Please upload your proteomics file." - - return string_output - - def select_columns_for_loaders(software, software_df:None): """ select intensity and index column depending on software @@ -116,11 +107,11 @@ def select_columns_for_loaders(software, software_df:None): st.selectbox( "Index Column", options=software_options.get(software).get("index_column"), - key="index_column", ) + else: - st.selectbox( + st.multiselect( "Intensity Columns", options=software_df.columns.to_list(), key="intensity_column", @@ -135,7 +126,6 @@ def select_columns_for_loaders(software, software_df:None): ) - def load_proteomics_data(uploaded_file, intensity_column, index_column, software): """load software file into loader object from alphastats""" loader = software_options.get(software)["loader_function"]( @@ -159,7 +149,7 @@ def select_sample_column_metadata(df, software): ) st.write( - f"Select column that contains sample IDs matching the sample names described" + f"Select column that contains sample IDs matching the sample names described " + f"in {software_options.get(software).get('import_file')}" ) @@ -174,7 +164,7 @@ def select_sample_column_metadata(df, software): def upload_softwarefile(software): softwarefile = st.file_uploader( - print_software_import_info(software=software), + software_options.get(software).get("import_file"), type=["csv", "tsv", "txt", "hdf"], ) @@ -191,7 +181,7 @@ def upload_softwarefile(software): ) st.dataframe(softwarefile_df.head(5)) - select_columns_for_loaders(software=software) + select_columns_for_loaders(software=software, software_df=softwarefile_df) if ( "intensity_column" in st.session_state @@ -233,7 +223,7 @@ def upload_metadatafile(software): "Upload metadata file. with information about your samples", key="metadatafile", ) - if metadatafile_upload is not None: + if metadatafile_upload is not None and st.session_state.loader is not None: metadatafile_df = read_uploaded_file_into_df(st.session_state.metadatafile) # display metadata @@ -257,18 +247,20 @@ def upload_metadatafile(software): display_loaded_dataset() - create_metadata_file() - st.write("Download the template file and add additional information as columns to your samples such as disease group. " + if st.session_state.loader is not None: + create_metadata_file() + st.write("Download the template file and add additional information as " + + "columns to your samples such as disease group. " + "Upload the updated metadata file.") + if st.session_state.loader is not None: + if st.button("Create a DataSet without metadata"): + st.session_state["dataset"] = DataSet(loader=st.session_state.loader) + st.session_state["metadata_columns"] = ["sample"] - if st.button("Create a DataSet without metadata"): - st.session_state["dataset"] = DataSet(loader=st.session_state.loader) - st.session_state["metadata_columns"] = ["sample"] - - load_options() + load_options() - display_loaded_dataset() + display_loaded_dataset() def load_sample_data(): @@ -280,7 +272,6 @@ def load_sample_data(): filepath= os.path.join(folder_to_load, "proteinGroups.txt") metadatapath= os.path.join(folder_to_load, "metadata.xlsx") - loader = MaxQuantLoader(file=filepath) ds = DataSet( loader=loader, metadata_path=metadatapath, sample_column="sample" @@ -309,29 +300,18 @@ def load_sample_data(): def import_data(): + options = ["", - "MaxQuant", - "AlphaPept", - "DIANN", - "Fragpipe", - "Spectronaut", - "Other", - ], - + options=options, ) - session_state_empty = False if software != "