From e2e752107c9a311e3022de1a159f8863e9959c2c Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Wed, 13 Sep 2023 19:11:33 +0200 Subject: [PATCH 01/70] :sparkles: dump and rename peptide files with PEP score create a new intermediate dump of 7,444 HeLa runs --- project/erda_02_mq_count_features.ipynb | 98 ++++++++++++++++++++----- project/erda_02_mq_count_features.py | 21 +++++- vaep/io/data_objects.py | 3 +- 3 files changed, 102 insertions(+), 20 deletions(-) diff --git a/project/erda_02_mq_count_features.ipynb b/project/erda_02_mq_count_features.ipynb index bc1e89640..1d50f1f7d 100644 --- a/project/erda_02_mq_count_features.ipynb +++ b/project/erda_02_mq_count_features.ipynb @@ -10,7 +10,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "import os\n", @@ -53,7 +55,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml')\n", @@ -73,7 +77,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id\n", @@ -81,24 +87,37 @@ "df_ids" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Select files and create list of folders" + ] + }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "folders_dict = { sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids['Sample ID']}\n", "# folders_dict = {p.stem : p.parent / p.stem for p in folders_dict}\n", - "# folders_dict" + "# folders_dict\n", + "folders = [Path(folder_path) for folder_path in folders_dict.values()]\n" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "OVERWRITE = False\n", + "OVERWRITE = True\n", "\n", "from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES\n", "\n", @@ -115,7 +134,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "import random\n", @@ -129,7 +150,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "use_columns = mq_output.peptides.columns[33:45]\n", @@ -140,7 +163,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "df_json_string = df.to_json(orient='index', indent=4)\n", @@ -150,7 +175,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "df_csv = df.to_csv()\n", @@ -160,7 +187,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "pd.read_json(df_json_string, orient='index')" @@ -169,7 +198,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands" @@ -185,7 +216,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "peptide_counter = PeptideCounter(FNAME_C_PEPTIDES, overwrite=OVERWRITE)\n", @@ -195,7 +228,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "if peptide_counter.loaded:\n", @@ -222,10 +257,37 @@ "outputs": [], "source": [ "%%time\n", - "# folders = [Path(folder_path) for folder_path in folders_dict.values()]\n", "c = peptide_counter.sum_over_files(folders=folders)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "for k, v in peptide_counter.dumps.items():\n", + " old_name = v\n", + " new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv')\n", + " try:\n", + " os.rename(old_name, new_name)\n", + " except FileNotFoundError:\n", + " logging.warning(f\"File not found: {old_name}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "new_name" + ] + }, { "cell_type": "code", "execution_count": null, @@ -238,7 +300,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "# To share as python file\n", @@ -761,7 +825,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.15" + "version": "3.10.12" } }, "nbformat": 4, diff --git a/project/erda_02_mq_count_features.py b/project/erda_02_mq_count_features.py index e14a92657..80821096b 100644 --- a/project/erda_02_mq_count_features.py +++ b/project/erda_02_mq_count_features.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.1 # kernelspec: # display_name: Python 3 (ipykernel) # language: python @@ -67,13 +67,19 @@ df_ids = pd.read_csv(fn_id_old_new) df_ids +# %% [markdown] +# Select files and create list of folders + # %% folders_dict = { sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids['Sample ID']} # folders_dict = {p.stem : p.parent / p.stem for p in folders_dict} # folders_dict +folders = [Path(folder_path) for folder_path in folders_dict.values()] + # %% OVERWRITE = False +OVERWRITE = True from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES @@ -129,9 +135,20 @@ # %% # %%time -# folders = [Path(folder_path) for folder_path in folders_dict.values()] c = peptide_counter.sum_over_files(folders=folders) +# %% +for k, v in peptide_counter.dumps.items(): + old_name = v + new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv') + try: + os.rename(old_name, new_name) + except FileNotFoundError: + logging.warning(f"File not found: {old_name}") + +# %% +new_name + # %% c.most_common(10) # peptide_counter.counter.most_common(10) diff --git a/vaep/io/data_objects.py b/vaep/io/data_objects.py index 6540ecbad..8ffb62340 100644 --- a/vaep/io/data_objects.py +++ b/vaep/io/data_objects.py @@ -399,7 +399,7 @@ def __call__(self, folders, ### aggregated peptides # # check df for redundant information (same feature value for all entries) -usecols = mq.COLS_ + ['Potential contaminant', mq.mq_col.SEQUENCE] +usecols = mq.COLS_ + ['Potential contaminant', mq.mq_col.SEQUENCE, 'PEP'] def count_peptides(folders: List[Path], dump=True, @@ -426,6 +426,7 @@ def count_peptides(folders: List[Path], dump=True, d_dtypes_training_sample = { 'Sequence': pd.StringDtype(), 'Proteins': pd.StringDtype(), + 'PEP': pd.Float32Dtype(), 'Leading razor protein': pd.StringDtype(), 'Gene names': pd.StringDtype(), 'Intensity': pd.Int64Dtype() From 771178fc43dc7a12dc492893c5528cab6cef4d55 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 14 Sep 2023 11:28:30 +0200 Subject: [PATCH 02/70] :sparkles: KNN comp. in updated workflow (v2) - KNN dumps val and test data with specified "args.model_key" in "config.yaml" - update color palette for "unknown" models - make performance_plots.py more robust - training configs are created and saved on the fly (-> avoid separate model configs, collect all in one) R methods are fixed, no customization so far. To do this one would probably need to generate separte NBs for each method. --- project/01_1_train_KNN.ipynb | 57 +++--- project/01_1_train_KNN.py | 59 +++--- project/01_2_performance_plots.ipynb | 27 +-- project/01_2_performance_plots.py | 25 ++- .../knn_comparison/ald_pgs_all/README.md | 7 + .../knn_comparison/ald_pgs_all/config.yaml | 23 +++ .../knn_comparison/ald_pgs_all/split.yaml | 6 + .../knn_comparison/hela_pgs_large/README.md | 7 + .../knn_comparison/hela_pgs_large/config.yaml | 23 +++ .../hela_pgs_large/inspect_data.yaml | 11 ++ .../knn_comparison/hela_pgs_large/split.yaml | 3 + project/workflow/Snakefile_v2 | 182 ++++++++++++++++++ vaep/plotting/defaults.py | 4 +- 13 files changed, 356 insertions(+), 78 deletions(-) create mode 100644 project/config/knn_comparison/ald_pgs_all/README.md create mode 100644 project/config/knn_comparison/ald_pgs_all/config.yaml create mode 100644 project/config/knn_comparison/ald_pgs_all/split.yaml create mode 100644 project/config/knn_comparison/hela_pgs_large/README.md create mode 100644 project/config/knn_comparison/hela_pgs_large/config.yaml create mode 100644 project/config/knn_comparison/hela_pgs_large/inspect_data.yaml create mode 100644 project/config/knn_comparison/hela_pgs_large/split.yaml create mode 100644 project/workflow/Snakefile_v2 diff --git a/project/01_1_train_KNN.ipynb b/project/01_1_train_KNN.ipynb index 895914e80..5ff0cc428 100644 --- a/project/01_1_train_KNN.ipynb +++ b/project/01_1_train_KNN.ipynb @@ -66,25 +66,26 @@ "outputs": [], "source": [ "# files and folders\n", - "folder_experiment:str = 'runs/example' # Datasplit folder with data for experiment\n", - "folder_data:str = '' # specify data directory if needed\n", - "file_format: str = 'csv' # file format of create splits, default pickle (pkl)\n", - "fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv' # Machine parsed metadata from rawfile workflow\n", + "folder_experiment: str = 'runs/example' # Datasplit folder with data for experiment\n", + "folder_data: str = '' # specify data directory if needed\n", + "file_format: str = 'csv' # file format of create splits, default pickle (pkl)\n", + "# Machine parsed metadata from rawfile workflow\n", + "fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv'\n", "# training\n", - "epochs_max:int = 50 # Maximum number of epochs\n", + "epochs_max: int = 50 # Maximum number of epochs\n", "# early_stopping:bool = True # Wheather to use early stopping or not\n", - "batch_size:int = 64 # Batch size for training (and evaluation)\n", - "cuda:bool = True # Whether to use a GPU for training\n", + "batch_size: int = 64 # Batch size for training (and evaluation)\n", + "cuda: bool = True # Whether to use a GPU for training\n", "# model\n", - "neighbors:int = 3 # number of neigherst neighbors to use\n", - "force_train:bool = True # Force training when saved model could be used. Per default re-train model\n", - "sample_idx_position: int = 0 # position of index which is sample ID\n", - "model: str = 'KNN' # model name\n", - "model_key: str = 'KNN' # potentially alternative key for model (grid search)\n", - "save_pred_real_na: bool = True # Save all predictions for missing values\n", + "neighbors: int = 3 # number of neigherst neighbors to use\n", + "force_train: bool = True # Force training when saved model could be used. Per default re-train model\n", + "sample_idx_position: int = 0 # position of index which is sample ID\n", + "model: str = 'KNN' # model name\n", + "model_key: str = 'KNN' # potentially alternative key for model (grid search)\n", + "save_pred_real_na: bool = True # Save all predictions for missing values\n", "# metadata -> defaults for metadata extracted from machine data\n", - "meta_date_col: str = None # date column in meta data\n", - "meta_cat_col: str = None # category column in meta data" + "meta_date_col: str = None # date column in meta data\n", + "meta_cat_col: str = None # category column in meta data" ] }, { @@ -142,7 +143,7 @@ "metadata": {}, "outputs": [], "source": [ - "data = datasplits.DataSplits.from_folder(args.data, file_format=args.file_format) " + "data = datasplits.DataSplits.from_folder(args.data, file_format=args.file_format)" ] }, { @@ -201,7 +202,7 @@ "outputs": [], "source": [ "freq_feat = sampling.frequency_by_index(data.train_X, 0)\n", - "freq_feat.head() # training data" + "freq_feat.head() # training data" ] }, { @@ -217,7 +218,7 @@ "id": "382b887d", "metadata": {}, "source": [ - "The validation fake NA is used to by all models to evaluate training performance. " + "The validation fake NA is used to by all models to evaluate training performance." ] }, { @@ -316,7 +317,7 @@ "metadata": {}, "outputs": [], "source": [ - "val_pred_fake_na[args.model] = pred\n", + "val_pred_fake_na[args.model_key] = pred\n", "val_pred_fake_na" ] }, @@ -327,7 +328,7 @@ "metadata": {}, "outputs": [], "source": [ - "test_pred_fake_na[args.model] = pred\n", + "test_pred_fake_na[args.model_key] = pred\n", "test_pred_fake_na" ] }, @@ -382,8 +383,8 @@ "source": [ "## Comparisons\n", "\n", - "> Note: The interpolated values have less predictions for comparisons than the ones based on models (CF, DAE, VAE) \n", - "> The comparison is therefore not 100% fair as the interpolated samples will have more common ones (especailly the sparser the data) \n", + "> Note: The interpolated values have less predictions for comparisons than the ones based on models (CF, DAE, VAE)\n", + "> The comparison is therefore not 100% fair as the interpolated samples will have more common ones (especailly the sparser the data)\n", "> Could be changed." ] }, @@ -396,7 +397,7 @@ "\n", "- all measured (identified, observed) peptides in validation data\n", "\n", - "> Does not make to much sense to compare collab and AEs, \n", + "> Does not make to much sense to compare collab and AEs,\n", "> as the setup differs of training and validation data differs" ] }, @@ -437,7 +438,9 @@ "source": [ "### Test Datasplit\n", "\n", - "Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction." + "Fake NAs : Artificially created NAs. Some data was sampled and set\n", + "explicitly to misssing before it was fed to the model for\n", + "reconstruction." ] }, { @@ -519,7 +522,7 @@ "metadata": {}, "outputs": [], "source": [ - "figures # switch to fnames?" + "figures # switch to fnames?" ] }, { @@ -529,8 +532,8 @@ "metadata": {}, "outputs": [], "source": [ - "args.n_params = 1 # the number of neighbors to consider\n", - "args.dump(fname=args.out_models/ f\"model_config_{args.model_key}.yaml\")\n", + "args.n_params = 1 # the number of neighbors to consider\n", + "args.dump(fname=args.out_models / f\"model_config_{args.model_key}.yaml\")\n", "args" ] } diff --git a/project/01_1_train_KNN.py b/project/01_1_train_KNN.py index 5e8528b5c..ddc390066 100644 --- a/project/01_1_train_KNN.py +++ b/project/01_1_train_KNN.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -44,25 +44,26 @@ # %% tags=["parameters"] # files and folders -folder_experiment:str = 'runs/example' # Datasplit folder with data for experiment -folder_data:str = '' # specify data directory if needed -file_format: str = 'csv' # file format of create splits, default pickle (pkl) -fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv' # Machine parsed metadata from rawfile workflow +folder_experiment: str = 'runs/example' # Datasplit folder with data for experiment +folder_data: str = '' # specify data directory if needed +file_format: str = 'csv' # file format of create splits, default pickle (pkl) +# Machine parsed metadata from rawfile workflow +fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv' # training -epochs_max:int = 50 # Maximum number of epochs +epochs_max: int = 50 # Maximum number of epochs # early_stopping:bool = True # Wheather to use early stopping or not -batch_size:int = 64 # Batch size for training (and evaluation) -cuda:bool = True # Whether to use a GPU for training +batch_size: int = 64 # Batch size for training (and evaluation) +cuda: bool = True # Whether to use a GPU for training # model -neighbors:int = 3 # number of neigherst neighbors to use -force_train:bool = True # Force training when saved model could be used. Per default re-train model -sample_idx_position: int = 0 # position of index which is sample ID -model: str = 'KNN' # model name -model_key: str = 'KNN' # potentially alternative key for model (grid search) -save_pred_real_na: bool = True # Save all predictions for missing values +neighbors: int = 3 # number of neigherst neighbors to use +force_train: bool = True # Force training when saved model could be used. Per default re-train model +sample_idx_position: int = 0 # position of index which is sample ID +model: str = 'KNN' # model name +model_key: str = 'KNN' # potentially alternative key for model (grid search) +save_pred_real_na: bool = True # Save all predictions for missing values # metadata -> defaults for metadata extracted from machine data -meta_date_col: str = None # date column in meta data -meta_cat_col: str = None # category column in meta data +meta_date_col: str = None # date column in meta data +meta_cat_col: str = None # category column in meta data # %% [markdown] # Some argument transformations @@ -83,7 +84,7 @@ # ## Load data in long format # %% -data = datasplits.DataSplits.from_folder(args.data, file_format=args.file_format) +data = datasplits.DataSplits.from_folder(args.data, file_format=args.file_format) # %% [markdown] # data is loaded in long format @@ -106,13 +107,13 @@ # %% freq_feat = sampling.frequency_by_index(data.train_X, 0) -freq_feat.head() # training data +freq_feat.head() # training data # %% [markdown] # ### Simulated missing values # %% [markdown] -# The validation fake NA is used to by all models to evaluate training performance. +# The validation fake NA is used to by all models to evaluate training performance. # %% val_pred_fake_na = data.val_y.to_frame(name='observed') @@ -152,11 +153,11 @@ pred # %% -val_pred_fake_na[args.model] = pred +val_pred_fake_na[args.model_key] = pred val_pred_fake_na # %% -test_pred_fake_na[args.model] = pred +test_pred_fake_na[args.model_key] = pred test_pred_fake_na # %% [markdown] @@ -182,8 +183,8 @@ # %% [markdown] # ## Comparisons # -# > Note: The interpolated values have less predictions for comparisons than the ones based on models (CF, DAE, VAE) -# > The comparison is therefore not 100% fair as the interpolated samples will have more common ones (especailly the sparser the data) +# > Note: The interpolated values have less predictions for comparisons than the ones based on models (CF, DAE, VAE) +# > The comparison is therefore not 100% fair as the interpolated samples will have more common ones (especailly the sparser the data) # > Could be changed. # %% [markdown] @@ -191,7 +192,7 @@ # # - all measured (identified, observed) peptides in validation data # -# > Does not make to much sense to compare collab and AEs, +# > Does not make to much sense to compare collab and AEs, # > as the setup differs of training and validation data differs # %% @@ -208,7 +209,9 @@ # %% [markdown] # ### Test Datasplit # -# Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction. +# Fake NAs : Artificially created NAs. Some data was sampled and set +# explicitly to misssing before it was fed to the model for +# reconstruction. # %% added_metrics = d_metrics.add_metrics(test_pred_fake_na, 'test_fake_na') @@ -237,9 +240,9 @@ # ## Config # %% -figures # switch to fnames? +figures # switch to fnames? # %% -args.n_params = 1 # the number of neighbors to consider -args.dump(fname=args.out_models/ f"model_config_{args.model_key}.yaml") +args.n_params = 1 # the number of neighbors to consider +args.dump(fname=args.out_models / f"model_config_{args.model_key}.yaml") args diff --git a/project/01_2_performance_plots.ipynb b/project/01_2_performance_plots.ipynb index 76320a9d2..ce690ad6f 100644 --- a/project/01_2_performance_plots.ipynb +++ b/project/01_2_performance_plots.ipynb @@ -466,7 +466,8 @@ "metadata": {}, "outputs": [], "source": [ - "COLORS_TO_USE = vaep.plotting.defaults.assign_colors(list(k.upper() for k in ORDER_MODELS))" + "COLORS_TO_USE = vaep.plotting.defaults.assign_colors(list(k.upper() for k in ORDER_MODELS))\n", + "sns.color_palette(COLORS_TO_USE)" ] }, { @@ -549,7 +550,7 @@ "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), name=fname)\n", "\n", - "fname = args.out_figures/'pred_corr_val_per_sample.xlsx'\n", + "fname = args.out_figures / 'pred_corr_val_per_sample.xlsx'\n", "dumps[fname.stem] = fname\n", "with pd.ExcelWriter(fname) as w:\n", " corr_per_sample_val.describe().to_excel(w, sheet_name='summary')\n", @@ -663,7 +664,7 @@ "fig, ax = plt.subplots(figsize=(8, 3))\n", "ax, errors_binned = vaep.plotting.errors.plot_errors_binned(\n", " pred_val[\n", - " [TARGET_COL]+TOP_N_ORDER\n", + " [TARGET_COL] + TOP_N_ORDER\n", " ],\n", " ax=ax,\n", " palette=TOP_N_COLOR_PALETTE,\n", @@ -755,8 +756,8 @@ " mae_stats_ordered_val.loc['mean'],\n", " mae_stats_ordered_test.loc['mean'],\n", "],\n", - "axis=1,\n", - "keys=['val', 'test']\n", + " axis=1,\n", + " keys=['val', 'test']\n", ").sort_values(by='val')\n", "cp_mean_perf.to_excel(writer, sheet_name='cp_mean_perf', float_format='%.5f')\n", "cp_mean_perf" @@ -1115,9 +1116,13 @@ }, "outputs": [], "source": [ - "text = model_configs[[\"latent_dim\", \"hidden_layers\"]].apply(\n", - " build_text,\n", - " axis=1)\n", + "try:\n", + " text = model_configs[[\"latent_dim\", \"hidden_layers\"]].apply(\n", + " build_text,\n", + " axis=1)\n", + "except KeyError:\n", + " logger.warning(\"No model PIMMS models in comparsion. Using empty text\")\n", + " text = pd.Series('', index=model_configs.columns)\n", "\n", "_to_plot.loc[\"text\"] = text\n", "_to_plot = _to_plot.fillna('')\n", @@ -1183,7 +1188,7 @@ "\n", "ax, errors_binned = vaep.plotting.errors.plot_errors_by_median(\n", " pred=pred_test[\n", - " [TARGET_COL]+TOP_N_ORDER\n", + " [TARGET_COL] + TOP_N_ORDER\n", " ],\n", " feat_medians=data.train_X.median(),\n", " ax=ax,\n", @@ -1235,7 +1240,7 @@ "fig, ax = plt.subplots(figsize=(8, 2))\n", "ax, errors_binned = vaep.plotting.errors.plot_errors_binned(\n", " pred_test[\n", - " [TARGET_COL]+TOP_N_ORDER\n", + " [TARGET_COL] + TOP_N_ORDER\n", " ],\n", " ax=ax,\n", " palette=TOP_N_COLOR_PALETTE,\n", @@ -1291,7 +1296,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c2f3ebc5", + "id": "ce4f2c42", "metadata": {}, "outputs": [], "source": [] diff --git a/project/01_2_performance_plots.py b/project/01_2_performance_plots.py index 2060bba1d..c4146d138 100644 --- a/project/01_2_performance_plots.py +++ b/project/01_2_performance_plots.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -249,6 +249,7 @@ def build_text(s): # Could be extended to all supported imputation methods # %% COLORS_TO_USE = vaep.plotting.defaults.assign_colors(list(k.upper() for k in ORDER_MODELS)) +sns.color_palette(COLORS_TO_USE) # %% # For top_N -> define colors @@ -300,7 +301,7 @@ def build_text(s): figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) -fname = args.out_figures/'pred_corr_val_per_sample.xlsx' +fname = args.out_figures / 'pred_corr_val_per_sample.xlsx' dumps[fname.stem] = fname with pd.ExcelWriter(fname) as w: corr_per_sample_val.describe().to_excel(w, sheet_name='summary') @@ -351,7 +352,7 @@ def build_text(s): fig, ax = plt.subplots(figsize=(8, 3)) ax, errors_binned = vaep.plotting.errors.plot_errors_binned( pred_val[ - [TARGET_COL]+TOP_N_ORDER + [TARGET_COL] + TOP_N_ORDER ], ax=ax, palette=TOP_N_COLOR_PALETTE, @@ -398,8 +399,8 @@ def build_text(s): mae_stats_ordered_val.loc['mean'], mae_stats_ordered_test.loc['mean'], ], -axis=1, -keys=['val', 'test'] + axis=1, + keys=['val', 'test'] ).sort_values(by='val') cp_mean_perf.to_excel(writer, sheet_name='cp_mean_perf', float_format='%.5f') cp_mean_perf @@ -601,9 +602,13 @@ def highlight_min(s, color, tolerence=0.00001): _to_plot # %% -text = model_configs[["latent_dim", "hidden_layers"]].apply( - build_text, - axis=1) +try: + text = model_configs[["latent_dim", "hidden_layers"]].apply( + build_text, + axis=1) +except KeyError: + logger.warning("No model PIMMS models in comparsion. Using empty text") + text = pd.Series('', index=model_configs.columns) _to_plot.loc["text"] = text _to_plot = _to_plot.fillna('') @@ -643,7 +648,7 @@ def highlight_min(s, color, tolerence=0.00001): ax, errors_binned = vaep.plotting.errors.plot_errors_by_median( pred=pred_test[ - [TARGET_COL]+TOP_N_ORDER + [TARGET_COL] + TOP_N_ORDER ], feat_medians=data.train_X.median(), ax=ax, @@ -676,7 +681,7 @@ def highlight_min(s, color, tolerence=0.00001): fig, ax = plt.subplots(figsize=(8, 2)) ax, errors_binned = vaep.plotting.errors.plot_errors_binned( pred_test[ - [TARGET_COL]+TOP_N_ORDER + [TARGET_COL] + TOP_N_ORDER ], ax=ax, palette=TOP_N_COLOR_PALETTE, diff --git a/project/config/knn_comparison/ald_pgs_all/README.md b/project/config/knn_comparison/ald_pgs_all/README.md new file mode 100644 index 000000000..95ea87933 --- /dev/null +++ b/project/config/knn_comparison/ald_pgs_all/README.md @@ -0,0 +1,7 @@ +# KNN comparison + +for ALD protein groups dataset. + +```bash +snakemake -s workflow/Snakefile_v2 --configfile config/knn_comparison/ald_pgs_all/config.yaml -p -c1 -n +``` \ No newline at end of file diff --git a/project/config/knn_comparison/ald_pgs_all/config.yaml b/project/config/knn_comparison/ald_pgs_all/config.yaml new file mode 100644 index 000000000..d212ba056 --- /dev/null +++ b/project/config/knn_comparison/ald_pgs_all/config.yaml @@ -0,0 +1,23 @@ +config_split: config/knn_comparison/ald_pgs_all/split.yaml +config_train: runs/knn_comparison/ald_pgs_all/configs_train/train_{model}.yaml +folder_experiment: runs/knn_comparison/ald_pgs_all +fn_rawfile_metadata: data/ALD_study/processed/raw_meta.csv +file_format: pkl +cuda: True +models: + - Median: + model: Median + - 3NN: + neighbors: 3 + model: KNN + - 5NN: + neighbors: 5 + model: KNN + - 10NN: + neighbors: 10 + model: KNN + - 15NN: + neighbors: 15 + model: KNN +NAGuideR_methods: + - KNN_IMPUTE diff --git a/project/config/knn_comparison/ald_pgs_all/split.yaml b/project/config/knn_comparison/ald_pgs_all/split.yaml new file mode 100644 index 000000000..d2c0b6793 --- /dev/null +++ b/project/config/knn_comparison/ald_pgs_all/split.yaml @@ -0,0 +1,6 @@ +FN_INTENSITIES: data/ALD_study/processed/ald_plasma_proteinGroups.pkl +# fn_rawfile_metadata: data/ALD_study/processed/raw_meta.csv +sample_completeness: 0.5 +min_RT_time: 20 +column_names: + - PG.ProteinAccessions \ No newline at end of file diff --git a/project/config/knn_comparison/hela_pgs_large/README.md b/project/config/knn_comparison/hela_pgs_large/README.md new file mode 100644 index 000000000..b22dd0b33 --- /dev/null +++ b/project/config/knn_comparison/hela_pgs_large/README.md @@ -0,0 +1,7 @@ +# KNN comparison + +for large protein groups HeLa dataset. + +```bash +snakemake -s workflow/Snakefile_v2 --configfile config/knn_comparison/hela_pgs_large/config.yaml -p -c1 -n +``` \ No newline at end of file diff --git a/project/config/knn_comparison/hela_pgs_large/config.yaml b/project/config/knn_comparison/hela_pgs_large/config.yaml new file mode 100644 index 000000000..0b15d1da1 --- /dev/null +++ b/project/config/knn_comparison/hela_pgs_large/config.yaml @@ -0,0 +1,23 @@ +config_split: config/knn_comparison/hela_pgs_large/split.yaml +config_train: runs/knn_comparison/hela_pgs_large/configs_train/train_{model}.yaml +folder_experiment: runs/knn_comparison/hela_pgs_large +fn_rawfile_metadata: data/dev_datasets/df_intensities_proteinGroups_long/metadata.csv +file_format: csv +cuda: True +models: + - Median: + model: Median + - 3NN: + neighbors: 3 + model: KNN + - 5NN: + neighbors: 5 + model: KNN + - 10NN: + neighbors: 10 + model: KNN + - 15NN: + neighbors: 15 + model: KNN +NAGuideR_methods: + - KNN_IMPUTE diff --git a/project/config/knn_comparison/hela_pgs_large/inspect_data.yaml b/project/config/knn_comparison/hela_pgs_large/inspect_data.yaml new file mode 100644 index 000000000..abc129e66 --- /dev/null +++ b/project/config/knn_comparison/hela_pgs_large/inspect_data.yaml @@ -0,0 +1,11 @@ +FN_INTENSITIES: data/dev_datasets/df_intensities_proteinGroups_long/Q_Exactive_HF_X_Orbitrap_6070.pkl +FOLDER_EXPERIMENT: runs/knn_comparison/hela_pgs_large +N_FIRST_ROWS: +LOG_TRANSFORM: True +INDEX_COL: + - 0 + - 1 +LONG_FORMAT: True +COMPLETENESS_OVER_SAMPLES: 0.25 +MIN_FEAT_PER_SAMPLE: 0.4 +PG_SEPARATOR: ; diff --git a/project/config/knn_comparison/hela_pgs_large/split.yaml b/project/config/knn_comparison/hela_pgs_large/split.yaml new file mode 100644 index 000000000..675f1b785 --- /dev/null +++ b/project/config/knn_comparison/hela_pgs_large/split.yaml @@ -0,0 +1,3 @@ +FN_INTENSITIES: data/dev_datasets/df_intensities_proteinGroups_long/Q_Exactive_HF_X_Orbitrap_6070.pkl +sample_completeness: 0.5 +min_RT_time: 120 \ No newline at end of file diff --git a/project/workflow/Snakefile_v2 b/project/workflow/Snakefile_v2 new file mode 100644 index 000000000..b69d783fc --- /dev/null +++ b/project/workflow/Snakefile_v2 @@ -0,0 +1,182 @@ +""" +Document how all the notebooks for a single experiment are connected. +""" +from snakemake.logging import logger + +configfile: "config/single_dev_dataset/proteinGroups_N50/config.yaml" + +folder_experiment = config["folder_experiment"] +logger.info(f"{folder_experiment = }") + + +rule all: + input: + f"{folder_experiment}/figures/errors_binned_by_int_test.pdf", + f"{folder_experiment}/01_2_performance_summary.xlsx" + + +nb = "01_2_performance_plots.ipynb" + +print(config["models"]) + +# MODELS = config["models"].copy() + +MODELS = list() +model_configs = dict() +for m in config["models"]: + for model, cfg_model in m.items(): + MODELS.append(model) + model_configs[model] = dict(cfg_model) +else: + del model, cfg_model + +if config["NAGuideR_methods"]: + MODELS += config["NAGuideR_methods"] + +print(model_configs) + + +print(MODELS) + +# import pdb; pdb.set_trace() + +rule comparison: + input: + nb=nb, + runs=expand( + "{folder_experiment}/preds/pred_test_{model}.csv", + folder_experiment=folder_experiment, + model=MODELS, + ), + output: + xlsx="{folder_experiment}/01_2_performance_summary.xlsx", + pdf="{folder_experiment}/figures/errors_binned_by_int_test.pdf", + nb="{folder_experiment}" f"/{nb}", + params: + meta_data=config["fn_rawfile_metadata"], + models=",".join(MODELS), + shell: + "papermill {input.nb} {output.nb}" + " -r fn_rawfile_metadata {params.meta_data:q}" + " -r folder_experiment {wildcards.folder_experiment:q}" + " -r models {params.models:q}" + " && jupyter nbconvert --to html {output.nb}" + +########################################################################################## +# train NaGuideR methods +nb_stem = "01_1_transfer_NAGuideR_pred" +rule transform_NAGuideR_predictions: + input: + dumps=expand( + "{{folder_experiment}}/preds/pred_all_{method}.csv", + method=config["NAGuideR_methods"], + ), + nb=f"{nb_stem}.ipynb", + output: + # "{{folder_experiment}}/preds/pred_real_na_{method}.csv"), + expand( ( + "{{folder_experiment}}/preds/pred_val_{method}.csv", + "{{folder_experiment}}/preds/pred_test_{method}.csv"), + method=config["NAGuideR_methods"], + ), + nb="{folder_experiment}/01_1_transfer_NAGuideR_pred.ipynb", + benchmark: + "{folder_experiment}/"f"{nb_stem}.tsv", + params: + folder_experiment="{folder_experiment}", + # https://snakemake.readthedocs.io/en/stable/snakefiles/rules.html#non-file-parameters-for-rules + dumps_as_str=lambda wildcards, input: ','.join(input.dumps) + shell: + "papermill {input.nb} {output.nb}" + " -r folder_experiment {params.folder_experiment}" + " -p dumps {params.dumps_as_str}" + " && jupyter nbconvert --to html {output.nb}" + +rule train_NAGuideR_model: + input: + nb="01_1_train_NAGuideR_methods.ipynb", + train_split="{folder_experiment}/data/data_wide_sample_cols.csv", + output: + nb="{folder_experiment}/01_1_train_NAGuideR_{method}.ipynb", + dump=temp("{folder_experiment}/preds/pred_all_{method}.csv") + benchmark: + "{folder_experiment}/01_1_train_NAGuideR_{method}.tsv" + params: + folder_experiment="{folder_experiment}", + method="{method}", + shell: + "papermill {input.nb} {output.nb}" + " -r train_split {input.train_split}" + " -r method {params.method}" + " -r folder_experiment {params.folder_experiment}" + " && jupyter nbconvert --to html {output.nb}" + +rule transform_data_to_wide_format: + input: + nb="01_0_transform_data_to_wide_format.ipynb", + train_split="{folder_experiment}/data/train_X.csv", + output: + nb="{folder_experiment}/01_0_transform_data_to_wide_format.ipynb", + train_split=temp("{folder_experiment}/data/data_wide_sample_cols.csv"), + params: + folder_experiment="{folder_experiment}", + shell: + "papermill {input.nb} {output.nb}" + " -r folder_experiment {params.folder_experiment}" + " && jupyter nbconvert --to html {output.nb}" + +########################################################################################## +# train models in python +rule train_models: + input: + nb=lambda wildcards: "01_1_train_{}.ipynb".format(model_configs[wildcards.model]["model"]), + train_split="{folder_experiment}/data/train_X.csv", + configfile=config["config_train"], + output: + nb="{folder_experiment}/01_1_train_{model}.ipynb", + pred="{folder_experiment}/preds/pred_test_{model}.csv" + benchmark: + "{folder_experiment}/01_1_train_{model}.tsv" + params: + folder_experiment="{folder_experiment}", + meta_data=config["fn_rawfile_metadata"], + shell: + "papermill {input.nb} {output.nb}" + " -f {input.configfile}" + " -r folder_experiment {params.folder_experiment}" + " -p fn_rawfile_metadata {params.meta_data}" + " -r model_key {wildcards.model}" + " && jupyter nbconvert --to html {output.nb}" + +########################################################################################## +# create config file dumps for each model + +rule dump_train_config: + output: + configfile=config["config_train"] + run: + import yaml + with open(output.configfile, "w") as f: + yaml.dump(model_configs[wildcards.model], f) + +########################################################################################## +# Create Data splits +# separate workflow by level -> provide custom configs +nb = "01_0_split_data.ipynb" + +rule create_splits: + input: + nb=nb, + configfile=config["config_split"], + output: + train_split="{folder_experiment}/data/train_X.csv", + nb="{folder_experiment}" f"/{nb}", + params: + folder_experiment="{folder_experiment}", + meta_data=config["fn_rawfile_metadata"], + shell: + "papermill {input.nb} {output.nb}" + " -f {input.configfile}" + " -r folder_experiment {params.folder_experiment}" + " -p fn_rawfile_metadata {params.meta_data}" + " && jupyter nbconvert --to html {output.nb}" \ No newline at end of file diff --git a/vaep/plotting/defaults.py b/vaep/plotting/defaults.py index db00b29b9..637f0815c 100644 --- a/vaep/plotting/defaults.py +++ b/vaep/plotting/defaults.py @@ -6,7 +6,6 @@ # ! default seaborn color map only has 10 colors # https://seaborn.pydata.org/tutorial/color_palettes.html # sns.color_palette("husl", N) to get N distinct colors -# color_model_mapping = { 'KNN': sns.color_palette()[0], 'KNN_IMPUTE': sns.color_palette()[1], @@ -21,7 +20,8 @@ 'SEQKNN': sns.color_palette()[6], 'MICE-NORM': sns.color_palette()[1], } -other_colors = sns.color_palette()[8:] +# other_colors = sns.color_palette()[8:] +other_colors = sns.color_palette("husl", 20) def assign_colors(models): From afc4f027c7def2cfec38c12a1ad7e7759dada79e Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 15 Sep 2023 17:52:28 +0200 Subject: [PATCH 03/70] :sparkles: MCAR-MNAR sampling based on Lazar et. al. (2016) - below a quantile -> MNAR, select from there - quantile is defined based on overall frac of missing values - mix MCAR and MNAR - format and clean-up code in script --- project/01_0_split_data.ipynb | 527 ++++++++++++++++++---------------- project/01_0_split_data.py | 431 ++++++++++++++------------- vaep/plotting/data.py | 48 +++- 3 files changed, 553 insertions(+), 453 deletions(-) diff --git a/project/01_0_split_data.ipynb b/project/01_0_split_data.ipynb index f6df4bd16..5d0214392 100644 --- a/project/01_0_split_data.ipynb +++ b/project/01_0_split_data.ipynb @@ -16,10 +16,10 @@ "outputs": [], "source": [ "from pathlib import Path\n", - "\n", + "import logging\n", "from typing import Union, List\n", "\n", - "\n", + "from IPython.display import display\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", @@ -28,31 +28,31 @@ "\n", "import vaep\n", "from vaep.io.datasplits import DataSplits\n", - "from vaep.io import thermo_raw_files\n", "from vaep.sampling import feature_frequency, sample_data\n", "\n", "from vaep.analyzers import analyzers\n", - "from vaep.analyzers.analyzers import AnalyzePeptides\n", + "from vaep.analyzers.analyzers import AnalyzePeptides\n", "\n", "logger = vaep.logging.setup_nb_logger()\n", "logger.info(\"Split data and make diagnostic plots\")\n", + "logging.getLogger('fontTools').setLevel(logging.WARNING)\n", + "\n", "\n", - "def add_meta_data(analysis: AnalyzePeptides, df_meta: pd.DataFrame):\n", + "def add_meta_data(df: pd.DataFrame, df_meta: pd.DataFrame):\n", " try:\n", - " analysis.df = analysis.df.loc[df_meta.index]\n", + " df = df.loc[df_meta.index]\n", " except KeyError as e:\n", " logger.warning(e)\n", " logger.warning(\"Ignore missing samples in quantified samples\")\n", - " analysis.df = analysis.df.loc[analysis.df.index.intersection(\n", + " df = df.loc[df.index.intersection(\n", " df_meta.index)]\n", - "\n", - " analysis.df_meta = df_meta\n", - " return analysis\n", + " return df_meta\n", "\n", "\n", "pd.options.display.max_columns = 32\n", "plt.rcParams['figure.figsize'] = [4, 2]\n", - "vaep.plotting.make_large_descriptors(5)\n", + "\n", + "vaep.plotting.make_large_descriptors(6)\n", "\n", "figures = {} # collection of ax or figures\n", "dumps = {} # collection of data dumps" @@ -80,39 +80,35 @@ "cell_type": "code", "execution_count": null, "metadata": { - "lines_to_next_cell": 2, "tags": [ "parameters" ] }, "outputs": [], "source": [ - "# Sample (rows) intensiites for features (columns)\n", - "FN_INTENSITIES: str = 'data/dev_datasets/HeLa_6070/protein_groups_wide_N50.csv'\n", - "# Can be either a string or position (typical 0 for first column), or a list of these.\n", - "index_col: Union[str, int] = 0\n", - "# wide_format: bool = False # intensities in wide format (more memory efficient of csv). Default is long_format (more precise)\n", - "# Manuelly set column names (of Index object in columns)\n", - "column_names: List[str] = [\"Gene Names\"]\n", - "# Machine parsed metadata from raw file (see workflows/metadata), wide format per sample\n", - "fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv'\n", - "# Minimum number or fraction of feature prevalence across samples to be kept\n", - "feat_prevalence: Union[int, float] = 0.25\n", - "# Minimum number or fraction of total requested features per Sample\n", - "sample_completeness: Union[int, float] = 0.5\n", + "FN_INTENSITIES: str = 'data/dev_datasets/HeLa_6070/protein_groups_wide_N50.csv' # Sample (rows), features (columns)\n", + "index_col: Union[str, int] = 0 # Can be either a string or position (default 0 for first column), or a list of these.\n", + "column_names: List[str] = [\"Gene Names\"] # Manuelly set column names (of Index object in columns)\n", + "fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv' # metadata for samples (rows)\n", + "feat_prevalence: Union[int, float] = 0.25 # Minimum number or fraction of feature prevalence across samples to be kept\n", + "sample_completeness: Union[int, float] = 0.5 # Minimum number or fraction of total requested features per Sample\n", "select_N: int = None # only use latest N samples\n", - "sample_N: bool = False # if select_N, sample N randomly instead of using latest?\n", + "sample_N: bool = False # if select_N, sample N randomly instead of using latest N\n", "random_state: int = 42 # random state for reproducibility of splits\n", - "# based on raw file meta data, only take samples with RT > min_RT_time\n", - "min_RT_time: Union[int, float] = None\n", - "# Log transformation of initial data (select one of the existing in numpy)\n", - "logarithm: str = 'log2'\n", - "folder_experiment: str = f'runs/example'\n", - "folder_data: str = '' # specify data directory if needed\n", + "min_RT_time: Union[int, float] = None # based on raw file meta data, only take samples with RT > min_RT_time\n", + "logarithm: str = 'log2' # Log transformation of initial data (select one of the existing in numpy)\n", + "folder_experiment: str = 'runs/example' # folder to save figures and data dumps\n", + "folder_data: str = '' # specify special data directory if needed\n", "file_format: str = 'csv' # file format of create splits, default pickle (pkl)\n", "# metadata -> defaults for metadata extracted from machine data, used for plotting\n", "meta_date_col: str = None # date column in meta data\n", - "meta_cat_col: str = None # category column in meta data" + "meta_cat_col: str = None # category column in meta data\n", + "# train, validation and test data splits\n", + "frac_non_train: float = 0.1 # fraction of non training data (validation and test split)\n", + "frac_mnar: float = 0.0 # fraction of missing not at random data, rest: missing completely at random\n", + "\n", + "meta_date_col: str = 'Content Creation Date'\n", + "meta_cat_col: str = 'Software Version'" ] }, { @@ -187,6 +183,7 @@ "metadata": {}, "outputs": [], "source": [ + "! factor out file reading to a separate module, not class\n", "# AnalyzePeptides.from_csv\n", "constructor = getattr(AnalyzePeptides, FILE_FORMAT_TO_CONSTRUCTOR[FILE_EXT])\n", "analysis = constructor(fname=params.FN_INTENSITIES,\n", @@ -202,7 +199,8 @@ "log_fct = getattr(np, params.logarithm)\n", "analysis.log_transform(log_fct)\n", "logger.info(f\"{analysis = }\")\n", - "analysis.df" + "df = analysis.df\n", + "df" ] }, { @@ -213,8 +211,13 @@ }, "outputs": [], "source": [ - "ax = analysis.df.notna().sum(axis=0).to_frame(\n", - " analysis.df.columns.name).plot.box()\n", + "ax = (df\n", + " .notna()\n", + " .sum(axis=0)\n", + " .to_frame(df.columns.name)\n", + " .plot\n", + " .box()\n", + " )\n", "ax.set_ylabel('number of observation across samples')" ] }, @@ -228,7 +231,7 @@ "dumps[fname.name] = fname.as_posix()\n", "writer = pd.ExcelWriter(fname)\n", "\n", - "notna = analysis.df.notna()\n", + "notna = df.notna()\n", "data_stats_original = pd.concat(\n", " [\n", " notna.sum().describe().rename('feat_stats'),\n", @@ -258,15 +261,16 @@ " ret = \"_\".join(str(x) for x in seq)\n", " return ret\n", "\n", + "\n", "# ToDo: join multiindex samples indices (pkl dumps)\n", - "# if hasattr(analysis.df.columns, \"levels\"):\n", - "if isinstance(analysis.df.columns, pd.MultiIndex):\n", + "# if hasattr(df.columns, \"levels\"):\n", + "if isinstance(df.columns, pd.MultiIndex):\n", " logger.warning(\"combine MultiIndex columns to one feature column\")\n", - " print(analysis.df.columns[:10].map(join_as_str))\n", - " _new_name = join_as_str(analysis.df.columns.names)\n", - " analysis.df.columns = analysis.df.columns.map(join_as_str)\n", - " analysis.df.columns.name = _new_name\n", - " logger.warning(f\"New name: {analysis.df.columns.names = }\")" + " print(df.columns[:10].map(join_as_str))\n", + " _new_name = join_as_str(df.columns.names)\n", + " df.columns = df.columns.map(join_as_str)\n", + " df.columns.name = _new_name\n", + " logger.warning(f\"New name: {df.columns.names = }\")" ] }, { @@ -294,8 +298,8 @@ " if params.meta_cat_col:\n", " raise ValueError(\n", " f\"No metadata provided, but data column set: {params.meta_cat_col}\")\n", - " df_meta = pd.DataFrame(index=analysis.df.index)\n", - "df_meta = df_meta.loc[analysis.df.index.to_list()] # index is sample index\n", + " df_meta = pd.DataFrame(index=df.index)\n", + "df_meta = df_meta.loc[df.index.to_list()] # index is sample index\n", "if df_meta.index.name is None:\n", " df_meta.index.name = params.index_col[0]\n", "df_meta" @@ -304,7 +308,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ "if params.meta_date_col:\n", @@ -316,20 +322,6 @@ "df_meta" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "if df_meta.columns.isin(thermo_raw_files.cols_instrument).sum() == len(thermo_raw_files.cols_instrument):\n", - " display(df_meta.groupby(thermo_raw_files.cols_instrument)[\n", - " params.meta_date_col].agg(['count', 'min', 'max']))\n", - "else:\n", - " logger.info(\n", - " f\"Instrument column not found: {thermo_raw_files.cols_instrument}\")" - ] - }, { "cell_type": "code", "execution_count": null, @@ -364,7 +356,7 @@ " logger.info(msg)\n", " df_meta = df_meta.loc[mask_RT]\n", "else:\n", - " logger.warning(f\"Retention time filtering deactivated.\")" + " logger.warning(\"Retention time filtering deactivated.\")" ] }, { @@ -396,7 +388,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ "try:\n", @@ -409,65 +403,13 @@ " display(meta_stats.loc[:, (meta_stats.loc['std'] > 0.1)])" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Optional, if using ThermoRawFileParser: check some columns describing settings\n", - " - software can be updated: `Software Version`\n", - " - `mass resolution` setting for instrument\n", - " - colision type for MS2: `beam-type collision-induced dissocation`\n", - " - missing `dilution factor`\n", - " - omit (uncomment if needed):\n", - " - quite some variation due to `MS max charge`: omit\n", - " - variation by `injection volume setting` and instrument over time\n", - " - 500ng of peptides should be injected, based on concentration of peptides this setting is adjusted to get it" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "meta_raw_settings = [\n", - " 'Thermo Scientific instrument model',\n", - " 'instrument serial number',\n", - " 'Software Version',\n", - " # 'MS max charge',\n", - " 'mass resolution',\n", - " 'beam-type collision-induced dissociation',\n", - " # 'injection volume setting',\n", - " 'dilution factor',\n", - "]\n", - "\n", - "if df_meta.columns.isin(meta_raw_settings).sum() == len(meta_raw_settings):\n", - " display(\n", - " # index gives first example with this combination\n", - " df_meta[meta_raw_settings].drop_duplicates()\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- check for variation in `software Version` and `injection volume setting`\n", - "\n", - "\n", - "Update selection of samples based on metadata (e.g. minimal retention time)\n", - "- sort data the same as sorted meta data" - ] - }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "analysis = add_meta_data(analysis, df_meta=df_meta)" + "df_meta = add_meta_data(df, df_meta=df_meta)" ] }, { @@ -483,7 +425,7 @@ "metadata": {}, "outputs": [], "source": [ - "assert analysis.df.index.is_unique, \"Duplicates in index\"" + "assert df.index.is_unique, \"Duplicates in index\"" ] }, { @@ -504,21 +446,23 @@ "outputs": [], "source": [ "if params.select_N is not None:\n", - " params.select_N = min(params.select_N, len(analysis.df_meta))\n", + " params.select_N = min(params.select_N, len(df_meta))\n", " if params.sample_N:\n", - " analysis.df_meta = analysis.df_meta.sample(params.select_N)\n", + " df_meta = df_meta.sample(params.select_N)\n", " else:\n", - " analysis.df_meta = analysis.df_meta.iloc[-params.select_N:]\n", + " df_meta = df_meta.iloc[-params.select_N:]\n", "\n", - " analysis.df = analysis.df.loc[analysis.df_meta.index].dropna(\n", + " df = df.loc[df_meta.index].dropna(\n", " how='all', axis=1)\n", - " ax = analysis.df.T.describe().loc['count'].hist()\n", + " ax = df.T.describe().loc['count'].hist()\n", " _ = ax.set_title('histogram of features for all eligable samples')" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "source": [ "## First Step: Select features by prevalence\n", "- `feat_prevalence` across samples" @@ -530,9 +474,9 @@ "metadata": {}, "outputs": [], "source": [ - "freq_per_feature = analysis.df.notna().sum() # on wide format\n", + "freq_per_feature = df.notna().sum() # on wide format\n", "if isinstance(params.feat_prevalence, float):\n", - " N_samples = len(analysis.df_meta)\n", + " N_samples = len(df)\n", " logger.info(f\"Current number of samples: {N_samples}\")\n", " logger.info(\n", " f\"Feature has to be present in at least {params.feat_prevalence:.2%} of samples\")\n", @@ -546,13 +490,19 @@ "mask = freq_per_feature >= params.feat_prevalence\n", "logger.info(f\"Drop {(~mask).sum()} features\")\n", "freq_per_feature = freq_per_feature.loc[mask]\n", - "analysis.df = analysis.df.loc[:, mask]\n", - "analysis.N, analysis.M = analysis.df.shape\n", - "\n", + "df = df.loc[:, mask]\n", + "analysis.N, analysis.M = df.shape\n", "# # potentially create freq based on DataFrame\n", - "analysis.df\n", - "\n", - "notna = analysis.df.notna()\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "notna = df.notna()\n", "data_stats_filtered = pd.concat(\n", " [\n", " notna.sum().describe().rename('feat_stats'),\n", @@ -587,11 +537,11 @@ " msg = f'Fraction of minimum sample completeness over all features specified with: {params.sample_completeness}\\n'\n", " # assumes df in wide format\n", " params.overwrite_entry('sample_completeness', int(\n", - " analysis.df.shape[1] * params.sample_completeness))\n", + " df.shape[1] * params.sample_completeness))\n", " msg += f'This translates to a minimum number of features per sample (to be included): {params.sample_completeness}'\n", " logger.info(msg)\n", "\n", - "sample_counts = analysis.df.notna().sum(axis=1) # if DataFrame\n", + "sample_counts = df.notna().sum(axis=1) # if DataFrame\n", "sample_counts.describe()" ] }, @@ -604,8 +554,8 @@ "mask = sample_counts > params.sample_completeness\n", "msg = f'Drop {len(mask) - mask.sum()} of {len(mask)} initial samples.'\n", "print(msg)\n", - "analysis.df = analysis.df.loc[mask]\n", - "analysis.df = analysis.df.dropna(\n", + "df = df.loc[mask]\n", + "df = df.dropna(\n", " axis=1, how='all') # drop now missing features" ] }, @@ -615,8 +565,8 @@ "metadata": {}, "outputs": [], "source": [ - "params.N, params.M = analysis.df.shape # save data dimensions\n", - "params.used_samples = analysis.df.index.to_list()" + "params.N, params.M = df.shape # save data dimensions\n", + "params.used_samples = df.index.to_list()" ] }, { @@ -632,7 +582,7 @@ "metadata": {}, "outputs": [], "source": [ - "ax = analysis.df.notna().sum(axis=1).hist()\n", + "ax = df.notna().sum(axis=1).hist()\n", "ax.set_xlabel('features per eligable sample')\n", "ax.set_ylabel('observations')\n", "fname = params.out_figures / 'hist_features_per_sample'\n", @@ -648,7 +598,7 @@ }, "outputs": [], "source": [ - "ax = analysis.df.notna().sum(axis=0).sort_values().plot()\n", + "ax = df.notna().sum(axis=0).sort_values().plot()\n", "_new_labels = [l.get_text().split(';')[0] for l in ax.get_xticklabels()]\n", "_ = ax.set_xticklabels(_new_labels, rotation=45,\n", " horizontalalignment='right')\n", @@ -672,9 +622,9 @@ "metadata": {}, "outputs": [], "source": [ - "min_max = vaep.plotting.data.min_max(analysis.df.stack())\n", + "min_max = vaep.plotting.data.min_max(df.stack())\n", "ax, bins = vaep.plotting.data.plot_histogram_intensities(\n", - " analysis.df.stack(), min_max=min_max)\n", + " df.stack(), min_max=min_max)\n", "\n", "fname = params.out_figures / 'intensity_distribution_overall'\n", "figures[fname.stem] = fname\n", @@ -688,7 +638,7 @@ "outputs": [], "source": [ "ax = vaep.plotting.data.plot_feat_median_over_prop_missing(\n", - " data=analysis.df, type='scatter')\n", + " data=df, type='scatter')\n", "fname = params.out_figures / 'intensity_median_vs_prop_missing_scatter'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), fname)" @@ -701,7 +651,7 @@ "outputs": [], "source": [ "ax = vaep.plotting.data.plot_feat_median_over_prop_missing(\n", - " data=analysis.df, type='boxplot')\n", + " data=df, type='boxplot')\n", "fname = params.out_figures / 'intensity_median_vs_prop_missing_boxplot'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), fname)" @@ -714,13 +664,6 @@ "### Interactive and Single plots" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Scatter plots need to become interactive." - ] - }, { "cell_type": "code", "execution_count": null, @@ -737,9 +680,9 @@ "outputs": [], "source": [ "K = 2\n", - "analysis.df = analysis.df.astype(float)\n", + "df = df.astype(float)\n", "pcs = analysis.get_PCA(n_components=K) # should be renamed to get_PCs\n", - "pcs = pcs.iloc[:, :K].join(analysis.df_meta).join(sample_counts)\n", + "pcs = pcs.iloc[:, :K].join(df_meta).join(sample_counts)\n", "\n", "pcs_name = pcs.columns[:2]\n", "pcs_index_name = pcs.index.name\n", @@ -763,11 +706,11 @@ "outputs": [], "source": [ "if params.meta_cat_col:\n", - " fig, ax = plt.subplots(figsize=(2,2))\n", + " fig, ax = plt.subplots(figsize=(2, 2))\n", " analyzers.seaborn_scatter(\n", " pcs[pcs_name], ax, meta=pcs[params.meta_cat_col], title=f\"by {params.meta_cat_col}\")\n", " fname = (params.out_figures\n", - " / f'pca_sample_by_{\"_\".join(params.meta_cat_col.split())}')\n", + " / f'pca_sample_by_{\"_\".join(params.meta_cat_col.split())}')\n", " figures[fname.stem] = fname\n", " vaep.savefig(fig, fname)" ] @@ -791,7 +734,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "- software version: Does it make a difference?\n", "- size: number of features in a single sample" ] }, @@ -830,8 +772,8 @@ " # color=pcs['Software Version'],\n", " color=col_identified_feat,\n", " template='none',\n", - " width=1200, # 4 inches x 300 dpi\n", - " height=600 # 2 inches x 300 dpi\n", + " width=1200, # 4 inches x 300 dpi\n", + " height=600 # 2 inches x 300 dpi\n", ")\n", "fname = (params.out_figures\n", " / f'pca_sample_by_{\"_\".join(col_identified_feat.split())}_plotly.pdf')\n", @@ -853,7 +795,7 @@ "metadata": {}, "outputs": [], "source": [ - "analysis.df.head()" + "df.head()" ] }, { @@ -862,12 +804,12 @@ "metadata": {}, "outputs": [], "source": [ - "df = analysis.df\n", - "df = df.join(df_meta[params.meta_date_col])\n", - "df = df.set_index(params.meta_date_col).sort_index()\n", + "df_w_date = df.join(df_meta[params.meta_date_col])\n", + "df_w_date = df_w_date.set_index(params.meta_date_col).sort_index()\n", "if not params.meta_date_col == 'PlaceholderTime':\n", - " df.to_period('min')\n", - "df = df.T" + " df_w_date.to_period('min')\n", + "df_w_date = df_w_date.T\n", + "df_w_date" ] }, { @@ -876,13 +818,18 @@ "metadata": {}, "outputs": [], "source": [ - "ax = df.boxplot(rot=80, figsize=(8, 3), fontsize=5,\n", - " showfliers=False, showcaps=False)\n", + "ax = df_w_date.boxplot(rot=80,\n", + " figsize=(8, 3),\n", + " fontsize=6,\n", + " showfliers=False,\n", + " showcaps=False\n", + " )\n", "_ = vaep.plotting.select_xticks(ax)\n", "fig = ax.get_figure()\n", "fname = params.out_figures / 'median_boxplot'\n", "figures[fname.stem] = fname\n", - "vaep.savefig(fig, fname)" + "vaep.savefig(fig, fname)\n", + "del df_w_date" ] }, { @@ -898,7 +845,7 @@ "metadata": {}, "outputs": [], "source": [ - "df.stack().describe(percentiles=np.linspace(0.05, 0.95, 10))" + "df.stack().describe(percentiles=np.linspace(0.05, 0.95, 19).round(2))" ] }, { @@ -918,15 +865,14 @@ "source": [ "if not params.meta_date_col == 'PlaceholderTime':\n", " dates = df_meta[params.meta_date_col].sort_values()\n", - " # dates.name = 'date'\n", - " median_sample_intensity = (analysis.df\n", + " median_sample_intensity = (df\n", " .median(axis=1)\n", " .to_frame('median intensity'))\n", " median_sample_intensity = median_sample_intensity.join(dates)\n", "\n", " ax = median_sample_intensity.plot.scatter(x=dates.name, y='median intensity',\n", " rot=90,\n", - " fontsize='large',\n", + " # fontsize=6,\n", " figsize=(8, 2),\n", " s=5,\n", " xticks=vaep.plotting.select_dates(\n", @@ -948,40 +894,26 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Feature frequency in data\n", - "\n", - "- higher count, higher probability to be sampled into training data\n", - "- missing peptides are sampled both into training as well as into validation dataset\n", - "- everything not in training data is validation data\n", - "\n", - "Based on unmodified training data" + "## Feature frequency in data" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "msg = \"Total number of samples in training data split: {}\"\n", - "print(msg.format(len(analysis.df)))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ - "# # analysis.splits.to_wide_format()\n", - "# assert analysis.splits is splits, \"Sanity check failed.\"" + "msg = \"Total number of samples in data: {}\"\n", + "print(msg.format(len(df)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Recalculate feature frequency after selecting some samples" + "Recalculate feature frequency after selecting samples" ] }, { @@ -990,14 +922,16 @@ "metadata": {}, "outputs": [], "source": [ - "freq_per_feature = feature_frequency(analysis.df)\n", + "freq_per_feature = feature_frequency(df)\n", "freq_per_feature" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ "# freq_per_feature.name = 'Gene names freq' # name it differently?\n", @@ -1010,29 +944,29 @@ "freq_per_feature.to_pickle(fname)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Conserning sampling with frequency weights:\n", - " - larger weight -> higher probablility of being sampled\n", - " - weights need to be alignable to index of original DataFrame before grouping (same index)" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Split: Train, validation and test data\n", "\n", - "- test data is in clinical language often denoted as independent validation cohort\n", - "- validation data (for model)" + "Select features as described in\n", + "> Lazar, Cosmin, Laurent Gatto, Myriam Ferro, Christophe Bruley, and Thomas Burger. 2016.\n", + "> “Accounting for the Multiple Natures of Missing Values in Label-Free Quantitative\n", + "> Proteomics Data Sets to Compare Imputation Strategies.”\n", + "> Journal of Proteome Research 15 (4): 1116–25.\n", + "\n", + "- select `frac_mnar` based on threshold matrix on quantile of overall frac of data to be used\n", + " for validation and test data split, e.g. 0.1 = quantile(0.1)\n", + "- select frac_mnar from intensities selected using threshold matrix" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ "analysis.splits = DataSplits(is_wide_format=False)\n", @@ -1045,23 +979,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Sample targets (Fake NAs)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Add goldstandard targets for valiation and test data\n", - "- based on same day\n", - "- same instrument" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create some target values by sampling 5% of the validation and test data." + "Create some target values by sampling X% of the validation and test data.\n", + "Simulated missing values are not used for validation and testing." ] }, { @@ -1080,15 +999,87 @@ "metadata": {}, "outputs": [], "source": [ - "fake_na, splits.train_X = sample_data(analysis.df_long.squeeze(),\n", - " sample_index_to_drop=0,\n", - " weights=freq_per_feature,\n", - " frac=0.1,\n", - " random_state=params.random_state,)\n", - "assert len(splits.train_X) > len(fake_na)\n", - "splits.val_y = fake_na.sample(frac=0.5, random_state=params.random_state).sort_index()\n", - "splits.test_y = fake_na.loc[fake_na.index.difference(splits.val_y.index)]\n", - "# splits" + "# if not mnar:\n", + "# fake_na, splits.train_X = sample_data(analysis.df_long.squeeze(),\n", + "# sample_index_to_drop=0,\n", + "# # weights=freq_per_feature,\n", + "# frac=0.1,\n", + "# random_state=params.random_state,)\n", + "# assert len(splits.train_X) > len(fake_na)\n", + "! move parameter checks to start of script\n", + "if 0.0 <= params.frac_mnar <= 1.0:\n", + " fig, axes = plt.subplots(1, 2, figsize=(8, 2))\n", + " quantile_frac = analysis.df_long.quantile(params.frac_non_train)\n", + " rng = np.random.default_rng(params.random_state)\n", + " threshold = pd.Series(rng.normal(loc=float(quantile_frac),\n", + " scale=float(0.3 * analysis.df_long.std()),\n", + " size=len(analysis.df_long),\n", + " ),\n", + " index=analysis.df_long.index,\n", + " )\n", + " # plot data vs threshold data\n", + " ax = axes[0]\n", + " from functools import partial\n", + " plot_histogram_intensities = partial(vaep.plotting.data.plot_histogram_intensities,\n", + " min_max=min_max,\n", + " alpha=0.8)\n", + " plot_histogram_intensities(\n", + " analysis.df_long.squeeze(),\n", + " ax=ax,\n", + " label='observed')\n", + " plot_histogram_intensities(\n", + " threshold,\n", + " ax=ax,\n", + " label='thresholds')\n", + " ax.legend()\n", + " # select MNAR (intensity between randomly sampled threshold)\n", + " mask = analysis.df_long.squeeze() < threshold\n", + " ! subsample to have exact fraction of MNAR?\n", + " N = len(analysis.df_long)\n", + " logger.info(f\"{int(N * params.frac_non_train) = :,d}\")\n", + " N_MNAR = int(params.frac_non_train * params.frac_mnar * N)\n", + " fake_na_mnar = analysis.df_long.loc[mask]\n", + " if len(fake_na_mnar) > N_MNAR:\n", + " fake_na_mnar = fake_na_mnar.sample(N_MNAR,\n", + " random_state=params.random_state)\n", + " splits.train_X = analysis.df_long.loc[\n", + " analysis.df_long.index.difference(\n", + " fake_na_mnar.index)\n", + " ]\n", + " logger.info(f\"{len(fake_na_mnar) = :,d}\")\n", + " N_MCAR = int(N * (1 - params.frac_mnar) * params.frac_non_train)\n", + " fake_na_mcar = splits.train_X.sample(N_MCAR,\n", + " random_state=params.random_state)\n", + " logger.info(f\"{len(fake_na_mcar) = :,d}\")\n", + " splits.train_X = (splits\n", + " .train_X\n", + " .loc[splits\n", + " .train_X\n", + " .index\n", + " .difference(\n", + " fake_na_mcar.index)]\n", + " ).squeeze()\n", + " logger.info(f\"{len(splits.train_X) = :,d}\")\n", + " fake_na = pd.concat([fake_na_mcar, fake_na_mnar]).squeeze()\n", + " logger.info(f\"{len(fake_na) = :,d}\")\n", + " ax = axes[1]\n", + " plot_histogram_intensities(\n", + " fake_na_mnar.squeeze(),\n", + " ax=ax,\n", + " label=f'MNAR ({N_MNAR:,d})',\n", + " color='C2')\n", + " plot_histogram_intensities(\n", + " fake_na_mcar.squeeze(),\n", + " ax=ax,\n", + " color='C3',\n", + " label=f'MCAR ({N_MCAR:,d})')\n", + " ax.legend()\n", + " assert len(fake_na) + len(splits.train_X) == len(analysis.df_long)\n", + "else:\n", + " raise ValueError(f\"Invalid MNAR float value (should be betw. 0 and 1): {params.frac_mnar}\")\n", + "\n", + "splits.val_y = fake_na.sample(frac=0.5, random_state=params.random_state)\n", + "splits.test_y = fake_na.loc[fake_na.index.difference(splits.val_y.index)]" ] }, { @@ -1131,14 +1122,14 @@ "# per feature are allowd.\n", "\n", "diff = (splits\n", - " .val_y\n", - " .index\n", - " .levels[-1]\n", - " .difference(splits\n", - " .train_X\n", - " .index\n", - " .levels[-1]\n", - " ).to_list())\n", + " .val_y\n", + " .index\n", + " .levels[-1]\n", + " .difference(splits\n", + " .train_X\n", + " .index\n", + " .levels[-1]\n", + " ).to_list())\n", "if diff:\n", " to_remove = splits.val_y.loc[pd.IndexSlice[:, diff]]\n", " display(to_remove)\n", @@ -1156,14 +1147,14 @@ "outputs": [], "source": [ "diff = (splits\n", - " .test_y\n", - " .index\n", - " .levels[-1]\n", - " .difference(splits\n", - " .train_X\n", - " .index\n", - " .levels[-1]\n", - " ).to_list())\n", + " .test_y\n", + " .index\n", + " .levels[-1]\n", + " .difference(splits\n", + " .train_X\n", + " .index\n", + " .levels[-1]\n", + " ).to_list())\n", "if diff:\n", " to_remove = splits.test_y.loc[pd.IndexSlice[:, diff]]\n", " display(to_remove)\n", @@ -1228,7 +1219,7 @@ "splits_df['val'] = splits.val_y\n", "splits_df['test'] = splits.test_y\n", "stats_splits = splits_df.describe()\n", - "stats_splits.to_excel(writer, 'stats_splits', float_format='%.2f')\n", + "# stats_splits.to_excel(writer, 'stats_splits', float_format='%.2f')\n", "stats_splits" ] }, @@ -1263,7 +1254,7 @@ " bins=bins,\n", " ax=None,\n", " color='C0',\n", - "))\n", + " ))\n", "_ = (splits\n", " .val_y\n", " .plot\n", @@ -1292,7 +1283,7 @@ " legend=False,\n", " stacked=True,\n", " color=['C0', 'C1', 'C2'],\n", - " )\n", + " )\n", "ax.legend(_legend)\n", "ax.set_xlabel('Intensity bins')\n", "ax.yaxis.set_major_formatter(\"{x:,.0f}\")\n", @@ -1312,7 +1303,7 @@ " color=['C1', 'C2'],\n", " legend=False,\n", " stacked=True,\n", - " )\n", + " )\n", "ax.legend(_legend[1:])\n", "ax.set_xlabel('Intensity bins')\n", "ax.yaxis.set_major_formatter(\"{x:,.0f}\")\n", @@ -1363,6 +1354,40 @@ "vaep.savefig(ax.get_figure(), fname)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "lines_to_next_cell": 0 + }, + "outputs": [], + "source": [ + "medians = (splits\n", + " .train_X\n", + " .median()\n", + " .astype(int)\n", + " ).to_frame('median_floor')\n", + "\n", + "feat_with_median = medians.groupby('median_floor').size().rename('M feat')\n", + "medians = medians.join(feat_with_median, on='median_floor')\n", + "medians = medians.apply(lambda s: \"{:02,d} (N={:3,d})\".format(*s), axis=1)\n", + "\n", + "fig, ax = plt.subplots(figsize=(8, 2))\n", + "s = 1\n", + "s_axes = pd.DataFrame({'medians': medians,\n", + " 'validation split': splits.val_y.notna().sum(),\n", + " 'training split': splits.train_X.notna().sum()}\n", + " ).plot.box(by='medians',\n", + " subplots=True,\n", + " boxprops=dict(linewidth=s),\n", + " flierprops=dict(markersize=s),\n", + " ax=ax)\n", + "for ax in s_axes:\n", + " _ = ax.set_xticklabels(ax.get_xticklabels(),\n", + " rotation=45,\n", + " horizontalalignment='right')" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/project/01_0_split_data.py b/project/01_0_split_data.py index 48b1fa31d..9507aeb39 100644 --- a/project/01_0_split_data.py +++ b/project/01_0_split_data.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -20,10 +20,10 @@ # %% from pathlib import Path - +import logging from typing import Union, List - +from IPython.display import display import numpy as np import pandas as pd import matplotlib.pyplot as plt @@ -32,31 +32,31 @@ import vaep from vaep.io.datasplits import DataSplits -from vaep.io import thermo_raw_files from vaep.sampling import feature_frequency, sample_data from vaep.analyzers import analyzers -from vaep.analyzers.analyzers import AnalyzePeptides +from vaep.analyzers.analyzers import AnalyzePeptides logger = vaep.logging.setup_nb_logger() logger.info("Split data and make diagnostic plots") +logging.getLogger('fontTools').setLevel(logging.WARNING) + -def add_meta_data(analysis: AnalyzePeptides, df_meta: pd.DataFrame): +def add_meta_data(df: pd.DataFrame, df_meta: pd.DataFrame): try: - analysis.df = analysis.df.loc[df_meta.index] + df = df.loc[df_meta.index] except KeyError as e: logger.warning(e) logger.warning("Ignore missing samples in quantified samples") - analysis.df = analysis.df.loc[analysis.df.index.intersection( + df = df.loc[df.index.intersection( df_meta.index)] - - analysis.df_meta = df_meta - return analysis + return df_meta pd.options.display.max_columns = 32 plt.rcParams['figure.figsize'] = [4, 2] -vaep.plotting.make_large_descriptors(5) + +vaep.plotting.make_large_descriptors(6) figures = {} # collection of ax or figures dumps = {} # collection of data dumps @@ -70,33 +70,29 @@ def add_meta_data(analysis: AnalyzePeptides, df_meta: pd.DataFrame): args = dict(globals()).keys() # %% tags=["parameters"] -# Sample (rows) intensiites for features (columns) -FN_INTENSITIES: str = 'data/dev_datasets/HeLa_6070/protein_groups_wide_N50.csv' -# Can be either a string or position (typical 0 for first column), or a list of these. -index_col: Union[str, int] = 0 -# wide_format: bool = False # intensities in wide format (more memory efficient of csv). Default is long_format (more precise) -# Manuelly set column names (of Index object in columns) -column_names: List[str] = ["Gene Names"] -# Machine parsed metadata from raw file (see workflows/metadata), wide format per sample -fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv' -# Minimum number or fraction of feature prevalence across samples to be kept -feat_prevalence: Union[int, float] = 0.25 -# Minimum number or fraction of total requested features per Sample -sample_completeness: Union[int, float] = 0.5 +FN_INTENSITIES: str = 'data/dev_datasets/HeLa_6070/protein_groups_wide_N50.csv' # Sample (rows), features (columns) +index_col: Union[str, int] = 0 # Can be either a string or position (default 0 for first column), or a list of these. +column_names: List[str] = ["Gene Names"] # Manuelly set column names (of Index object in columns) +fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv' # metadata for samples (rows) +feat_prevalence: Union[int, float] = 0.25 # Minimum number or fraction of feature prevalence across samples to be kept +sample_completeness: Union[int, float] = 0.5 # Minimum number or fraction of total requested features per Sample select_N: int = None # only use latest N samples -sample_N: bool = False # if select_N, sample N randomly instead of using latest? +sample_N: bool = False # if select_N, sample N randomly instead of using latest N random_state: int = 42 # random state for reproducibility of splits -# based on raw file meta data, only take samples with RT > min_RT_time -min_RT_time: Union[int, float] = None -# Log transformation of initial data (select one of the existing in numpy) -logarithm: str = 'log2' -folder_experiment: str = f'runs/example' -folder_data: str = '' # specify data directory if needed +min_RT_time: Union[int, float] = None # based on raw file meta data, only take samples with RT > min_RT_time +logarithm: str = 'log2' # Log transformation of initial data (select one of the existing in numpy) +folder_experiment: str = 'runs/example' # folder to save figures and data dumps +folder_data: str = '' # specify special data directory if needed file_format: str = 'csv' # file format of create splits, default pickle (pkl) # metadata -> defaults for metadata extracted from machine data, used for plotting meta_date_col: str = None # date column in meta data meta_cat_col: str = None # category column in meta data +# train, validation and test data splits +frac_non_train: float = 0.1 # fraction of non training data (validation and test split) +frac_mnar: float = 0.0 # fraction of missing not at random data, rest: missing completely at random +meta_date_col: str = 'Content Creation Date' +meta_cat_col: str = 'Software Version' # %% args = vaep.nb.get_params(args, globals=globals()) @@ -132,6 +128,7 @@ def add_meta_data(analysis: AnalyzePeptides, df_meta: pd.DataFrame): f"File format (extension): {FILE_EXT} (!specifies data loading function!)") # %% +# ! factor out file reading to a separate module, not class # AnalyzePeptides.from_csv constructor = getattr(AnalyzePeptides, FILE_FORMAT_TO_CONSTRUCTOR[FILE_EXT]) analysis = constructor(fname=params.FN_INTENSITIES, @@ -147,11 +144,17 @@ def add_meta_data(analysis: AnalyzePeptides, df_meta: pd.DataFrame): log_fct = getattr(np, params.logarithm) analysis.log_transform(log_fct) logger.info(f"{analysis = }") -analysis.df +df = analysis.df +df # %% -ax = analysis.df.notna().sum(axis=0).to_frame( - analysis.df.columns.name).plot.box() +ax = (df + .notna() + .sum(axis=0) + .to_frame(df.columns.name) + .plot + .box() + ) ax.set_ylabel('number of observation across samples') @@ -160,7 +163,7 @@ def add_meta_data(analysis: AnalyzePeptides, df_meta: pd.DataFrame): dumps[fname.name] = fname.as_posix() writer = pd.ExcelWriter(fname) -notna = analysis.df.notna() +notna = df.notna() data_stats_original = pd.concat( [ notna.sum().describe().rename('feat_stats'), @@ -181,15 +184,16 @@ def join_as_str(seq): ret = "_".join(str(x) for x in seq) return ret + # ToDo: join multiindex samples indices (pkl dumps) -# if hasattr(analysis.df.columns, "levels"): -if isinstance(analysis.df.columns, pd.MultiIndex): +# if hasattr(df.columns, "levels"): +if isinstance(df.columns, pd.MultiIndex): logger.warning("combine MultiIndex columns to one feature column") - print(analysis.df.columns[:10].map(join_as_str)) - _new_name = join_as_str(analysis.df.columns.names) - analysis.df.columns = analysis.df.columns.map(join_as_str) - analysis.df.columns.name = _new_name - logger.warning(f"New name: {analysis.df.columns.names = }") + print(df.columns[:10].map(join_as_str)) + _new_name = join_as_str(df.columns.names) + df.columns = df.columns.map(join_as_str) + df.columns.name = _new_name + logger.warning(f"New name: {df.columns.names = }") # %% [markdown] # ## Machine metadata @@ -207,8 +211,8 @@ def join_as_str(seq): if params.meta_cat_col: raise ValueError( f"No metadata provided, but data column set: {params.meta_cat_col}") - df_meta = pd.DataFrame(index=analysis.df.index) -df_meta = df_meta.loc[analysis.df.index.to_list()] # index is sample index + df_meta = pd.DataFrame(index=df.index) +df_meta = df_meta.loc[df.index.to_list()] # index is sample index if df_meta.index.name is None: df_meta.index.name = params.index_col[0] df_meta @@ -222,13 +226,6 @@ def join_as_str(seq): df_meta[params.meta_date_col] = range(len(df_meta)) df_meta -# %% -if df_meta.columns.isin(thermo_raw_files.cols_instrument).sum() == len(thermo_raw_files.cols_instrument): - display(df_meta.groupby(thermo_raw_files.cols_instrument)[ - params.meta_date_col].agg(['count', 'min', 'max'])) -else: - logger.info( - f"Instrument column not found: {thermo_raw_files.cols_instrument}") # %% df_meta.describe(datetime_is_numeric=True, @@ -249,7 +246,7 @@ def join_as_str(seq): logger.info(msg) df_meta = df_meta.loc[mask_RT] else: - logger.warning(f"Retention time filtering deactivated.") + logger.warning("Retention time filtering deactivated.") # %% df_meta = df_meta.sort_values(params.meta_date_col) @@ -271,51 +268,15 @@ def join_as_str(seq): if 'unique' in meta_stats.index: display(meta_stats.loc[:, (meta_stats.loc['std'] > 0.1)]) -# %% [markdown] -# Optional, if using ThermoRawFileParser: check some columns describing settings -# - software can be updated: `Software Version` -# - `mass resolution` setting for instrument -# - colision type for MS2: `beam-type collision-induced dissocation` -# - missing `dilution factor` -# - omit (uncomment if needed): -# - quite some variation due to `MS max charge`: omit -# - variation by `injection volume setting` and instrument over time -# - 500ng of peptides should be injected, based on concentration of peptides this setting is adjusted to get it - -# %% -meta_raw_settings = [ - 'Thermo Scientific instrument model', - 'instrument serial number', - 'Software Version', - # 'MS max charge', - 'mass resolution', - 'beam-type collision-induced dissociation', - # 'injection volume setting', - 'dilution factor', -] - -if df_meta.columns.isin(meta_raw_settings).sum() == len(meta_raw_settings): - display( - # index gives first example with this combination - df_meta[meta_raw_settings].drop_duplicates() - ) - - -# %% [markdown] -# - check for variation in `software Version` and `injection volume setting` -# -# -# Update selection of samples based on metadata (e.g. minimal retention time) -# - sort data the same as sorted meta data # %% -analysis = add_meta_data(analysis, df_meta=df_meta) +df_meta = add_meta_data(df, df_meta=df_meta) # %% [markdown] # Ensure unique indices # %% -assert analysis.df.index.is_unique, "Duplicates in index" +assert df.index.is_unique, "Duplicates in index" # %% [markdown] # ## Select a subset of samples if specified (reduce the number of samples) @@ -326,25 +287,26 @@ def join_as_str(seq): # %% if params.select_N is not None: - params.select_N = min(params.select_N, len(analysis.df_meta)) + params.select_N = min(params.select_N, len(df_meta)) if params.sample_N: - analysis.df_meta = analysis.df_meta.sample(params.select_N) + df_meta = df_meta.sample(params.select_N) else: - analysis.df_meta = analysis.df_meta.iloc[-params.select_N:] + df_meta = df_meta.iloc[-params.select_N:] - analysis.df = analysis.df.loc[analysis.df_meta.index].dropna( + df = df.loc[df_meta.index].dropna( how='all', axis=1) - ax = analysis.df.T.describe().loc['count'].hist() + ax = df.T.describe().loc['count'].hist() _ = ax.set_title('histogram of features for all eligable samples') # %% [markdown] # ## First Step: Select features by prevalence # - `feat_prevalence` across samples + # %% -freq_per_feature = analysis.df.notna().sum() # on wide format +freq_per_feature = df.notna().sum() # on wide format if isinstance(params.feat_prevalence, float): - N_samples = len(analysis.df_meta) + N_samples = len(df) logger.info(f"Current number of samples: {N_samples}") logger.info( f"Feature has to be present in at least {params.feat_prevalence:.2%} of samples") @@ -358,13 +320,13 @@ def join_as_str(seq): mask = freq_per_feature >= params.feat_prevalence logger.info(f"Drop {(~mask).sum()} features") freq_per_feature = freq_per_feature.loc[mask] -analysis.df = analysis.df.loc[:, mask] -analysis.N, analysis.M = analysis.df.shape - +df = df.loc[:, mask] +analysis.N, analysis.M = df.shape # # potentially create freq based on DataFrame -analysis.df +df -notna = analysis.df.notna() +# %% +notna = df.notna() data_stats_filtered = pd.concat( [ notna.sum().describe().rename('feat_stats'), @@ -385,30 +347,30 @@ def join_as_str(seq): msg = f'Fraction of minimum sample completeness over all features specified with: {params.sample_completeness}\n' # assumes df in wide format params.overwrite_entry('sample_completeness', int( - analysis.df.shape[1] * params.sample_completeness)) + df.shape[1] * params.sample_completeness)) msg += f'This translates to a minimum number of features per sample (to be included): {params.sample_completeness}' logger.info(msg) -sample_counts = analysis.df.notna().sum(axis=1) # if DataFrame +sample_counts = df.notna().sum(axis=1) # if DataFrame sample_counts.describe() # %% mask = sample_counts > params.sample_completeness msg = f'Drop {len(mask) - mask.sum()} of {len(mask)} initial samples.' print(msg) -analysis.df = analysis.df.loc[mask] -analysis.df = analysis.df.dropna( +df = df.loc[mask] +df = df.dropna( axis=1, how='all') # drop now missing features # %% -params.N, params.M = analysis.df.shape # save data dimensions -params.used_samples = analysis.df.index.to_list() +params.N, params.M = df.shape # save data dimensions +params.used_samples = df.index.to_list() # %% [markdown] # ### Histogram of features per sample # %% -ax = analysis.df.notna().sum(axis=1).hist() +ax = df.notna().sum(axis=1).hist() ax.set_xlabel('features per eligable sample') ax.set_ylabel('observations') fname = params.out_figures / 'hist_features_per_sample' @@ -416,7 +378,7 @@ def join_as_str(seq): vaep.savefig(ax.get_figure(), fname) # %% -ax = analysis.df.notna().sum(axis=0).sort_values().plot() +ax = df.notna().sum(axis=0).sort_values().plot() _new_labels = [l.get_text().split(';')[0] for l in ax.get_xticklabels()] _ = ax.set_xticklabels(_new_labels, rotation=45, horizontalalignment='right') @@ -431,9 +393,9 @@ def join_as_str(seq): # ### Number off observations accross feature value # %% -min_max = vaep.plotting.data.min_max(analysis.df.stack()) +min_max = vaep.plotting.data.min_max(df.stack()) ax, bins = vaep.plotting.data.plot_histogram_intensities( - analysis.df.stack(), min_max=min_max) + df.stack(), min_max=min_max) fname = params.out_figures / 'intensity_distribution_overall' figures[fname.stem] = fname @@ -441,14 +403,14 @@ def join_as_str(seq): # %% ax = vaep.plotting.data.plot_feat_median_over_prop_missing( - data=analysis.df, type='scatter') + data=df, type='scatter') fname = params.out_figures / 'intensity_median_vs_prop_missing_scatter' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), fname) # %% ax = vaep.plotting.data.plot_feat_median_over_prop_missing( - data=analysis.df, type='boxplot') + data=df, type='boxplot') fname = params.out_figures / 'intensity_median_vs_prop_missing_boxplot' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), fname) @@ -456,17 +418,14 @@ def join_as_str(seq): # %% [markdown] # ### Interactive and Single plots -# %% [markdown] -# Scatter plots need to become interactive. - # %% sample_counts.name = 'identified features' # %% K = 2 -analysis.df = analysis.df.astype(float) +df = df.astype(float) pcs = analysis.get_PCA(n_components=K) # should be renamed to get_PCs -pcs = pcs.iloc[:, :K].join(analysis.df_meta).join(sample_counts) +pcs = pcs.iloc[:, :K].join(df_meta).join(sample_counts) pcs_name = pcs.columns[:2] pcs_index_name = pcs.index.name @@ -478,11 +437,11 @@ def join_as_str(seq): # %% if params.meta_cat_col: - fig, ax = plt.subplots(figsize=(2,2)) + fig, ax = plt.subplots(figsize=(2, 2)) analyzers.seaborn_scatter( pcs[pcs_name], ax, meta=pcs[params.meta_cat_col], title=f"by {params.meta_cat_col}") fname = (params.out_figures - / f'pca_sample_by_{"_".join(params.meta_cat_col.split())}') + / f'pca_sample_by_{"_".join(params.meta_cat_col.split())}') figures[fname.stem] = fname vaep.savefig(fig, fname) @@ -496,7 +455,6 @@ def join_as_str(seq): vaep.savefig(fig, fname) # %% [markdown] -# - software version: Does it make a difference? # - size: number of features in a single sample # %% @@ -523,8 +481,8 @@ def join_as_str(seq): # color=pcs['Software Version'], color=col_identified_feat, template='none', - width=1200, # 4 inches x 300 dpi - height=600 # 2 inches x 300 dpi + width=1200, # 4 inches x 300 dpi + height=600 # 2 inches x 300 dpi ) fname = (params.out_figures / f'pca_sample_by_{"_".join(col_identified_feat.split())}_plotly.pdf') @@ -536,30 +494,35 @@ def join_as_str(seq): # ## Sample Medians and percentiles # %% -analysis.df.head() +df.head() # %% -df = analysis.df -df = df.join(df_meta[params.meta_date_col]) -df = df.set_index(params.meta_date_col).sort_index() +df_w_date = df.join(df_meta[params.meta_date_col]) +df_w_date = df_w_date.set_index(params.meta_date_col).sort_index() if not params.meta_date_col == 'PlaceholderTime': - df.to_period('min') -df = df.T + df_w_date.to_period('min') +df_w_date = df_w_date.T +df_w_date # %% -ax = df.boxplot(rot=80, figsize=(8, 3), fontsize=5, - showfliers=False, showcaps=False) +ax = df_w_date.boxplot(rot=80, + figsize=(8, 3), + fontsize=6, + showfliers=False, + showcaps=False + ) _ = vaep.plotting.select_xticks(ax) fig = ax.get_figure() fname = params.out_figures / 'median_boxplot' figures[fname.stem] = fname vaep.savefig(fig, fname) +del df_w_date # %% [markdown] # Percentiles of intensities in dataset # %% -df.stack().describe(percentiles=np.linspace(0.05, 0.95, 10)) +df.stack().describe(percentiles=np.linspace(0.05, 0.95, 19).round(2)) # %% [markdown] # ### Plot sample median over time @@ -569,15 +532,14 @@ def join_as_str(seq): # %% if not params.meta_date_col == 'PlaceholderTime': dates = df_meta[params.meta_date_col].sort_values() - # dates.name = 'date' - median_sample_intensity = (analysis.df + median_sample_intensity = (df .median(axis=1) .to_frame('median intensity')) median_sample_intensity = median_sample_intensity.join(dates) ax = median_sample_intensity.plot.scatter(x=dates.name, y='median intensity', rot=90, - fontsize='large', + # fontsize=6, figsize=(8, 2), s=5, xticks=vaep.plotting.select_dates( @@ -592,26 +554,17 @@ def join_as_str(seq): # %% [markdown] # ## Feature frequency in data -# -# - higher count, higher probability to be sampled into training data -# - missing peptides are sampled both into training as well as into validation dataset -# - everything not in training data is validation data -# -# Based on unmodified training data # %% -msg = "Total number of samples in training data split: {}" -print(msg.format(len(analysis.df))) +msg = "Total number of samples in data: {}" +print(msg.format(len(df))) -# %% -# # analysis.splits.to_wide_format() -# assert analysis.splits is splits, "Sanity check failed." # %% [markdown] -# Recalculate feature frequency after selecting some samples +# Recalculate feature frequency after selecting samples # %% -freq_per_feature = feature_frequency(analysis.df) +freq_per_feature = feature_frequency(df) freq_per_feature # %% @@ -624,16 +577,19 @@ def join_as_str(seq): dumps[fname.name] = fname freq_per_feature.to_pickle(fname) -# %% [markdown] -# Conserning sampling with frequency weights: -# - larger weight -> higher probablility of being sampled -# - weights need to be alignable to index of original DataFrame before grouping (same index) # %% [markdown] # ## Split: Train, validation and test data # -# - test data is in clinical language often denoted as independent validation cohort -# - validation data (for model) +# Select features as described in +# > Lazar, Cosmin, Laurent Gatto, Myriam Ferro, Christophe Bruley, and Thomas Burger. 2016. +# > “Accounting for the Multiple Natures of Missing Values in Label-Free Quantitative +# > Proteomics Data Sets to Compare Imputation Strategies.” +# > Journal of Proteome Research 15 (4): 1116–25. +# +# - select `frac_mnar` based on threshold matrix on quantile of overall frac of data to be used +# for validation and test data split, e.g. 0.1 = quantile(0.1) +# - select frac_mnar from intensities selected using threshold matrix # %% analysis.splits = DataSplits(is_wide_format=False) @@ -641,31 +597,97 @@ def join_as_str(seq): print(f"{analysis.splits = }") analysis.splits.__annotations__ -# %% [markdown] -# ### Sample targets (Fake NAs) # %% [markdown] -# Add goldstandard targets for valiation and test data -# - based on same day -# - same instrument - -# %% [markdown] -# Create some target values by sampling 5% of the validation and test data. +# Create some target values by sampling X% of the validation and test data. +# Simulated missing values are not used for validation and testing. # %% analysis.to_long_format(inplace=True) analysis.df_long # %% -fake_na, splits.train_X = sample_data(analysis.df_long.squeeze(), - sample_index_to_drop=0, - weights=freq_per_feature, - frac=0.1, - random_state=params.random_state,) -assert len(splits.train_X) > len(fake_na) -splits.val_y = fake_na.sample(frac=0.5, random_state=params.random_state).sort_index() +# if not mnar: +# fake_na, splits.train_X = sample_data(analysis.df_long.squeeze(), +# sample_index_to_drop=0, +# # weights=freq_per_feature, +# frac=0.1, +# random_state=params.random_state,) +# assert len(splits.train_X) > len(fake_na) +# ! move parameter checks to start of script +if 0.0 <= params.frac_mnar <= 1.0: + fig, axes = plt.subplots(1, 2, figsize=(8, 2)) + quantile_frac = analysis.df_long.quantile(params.frac_non_train) + rng = np.random.default_rng(params.random_state) + threshold = pd.Series(rng.normal(loc=float(quantile_frac), + scale=float(0.3 * analysis.df_long.std()), + size=len(analysis.df_long), + ), + index=analysis.df_long.index, + ) + # plot data vs threshold data + ax = axes[0] + from functools import partial + plot_histogram_intensities = partial(vaep.plotting.data.plot_histogram_intensities, + min_max=min_max, + alpha=0.8) + plot_histogram_intensities( + analysis.df_long.squeeze(), + ax=ax, + label='observed') + plot_histogram_intensities( + threshold, + ax=ax, + label='thresholds') + ax.legend() + # select MNAR (intensity between randomly sampled threshold) + mask = analysis.df_long.squeeze() < threshold + # ! subsample to have exact fraction of MNAR? + N = len(analysis.df_long) + logger.info(f"{int(N * params.frac_non_train) = :,d}") + N_MNAR = int(params.frac_non_train * params.frac_mnar * N) + fake_na_mnar = analysis.df_long.loc[mask] + if len(fake_na_mnar) > N_MNAR: + fake_na_mnar = fake_na_mnar.sample(N_MNAR, + random_state=params.random_state) + splits.train_X = analysis.df_long.loc[ + analysis.df_long.index.difference( + fake_na_mnar.index) + ] + logger.info(f"{len(fake_na_mnar) = :,d}") + N_MCAR = int(N * (1 - params.frac_mnar) * params.frac_non_train) + fake_na_mcar = splits.train_X.sample(N_MCAR, + random_state=params.random_state) + logger.info(f"{len(fake_na_mcar) = :,d}") + splits.train_X = (splits + .train_X + .loc[splits + .train_X + .index + .difference( + fake_na_mcar.index)] + ).squeeze() + logger.info(f"{len(splits.train_X) = :,d}") + fake_na = pd.concat([fake_na_mcar, fake_na_mnar]).squeeze() + logger.info(f"{len(fake_na) = :,d}") + ax = axes[1] + plot_histogram_intensities( + fake_na_mnar.squeeze(), + ax=ax, + label=f'MNAR ({N_MNAR:,d})', + color='C2') + plot_histogram_intensities( + fake_na_mcar.squeeze(), + ax=ax, + color='C3', + label=f'MCAR ({N_MCAR:,d})') + ax.legend() + assert len(fake_na) + len(splits.train_X) == len(analysis.df_long) +else: + raise ValueError(f"Invalid MNAR float value (should be betw. 0 and 1): {params.frac_mnar}") + +splits.val_y = fake_na.sample(frac=0.5, random_state=params.random_state) splits.test_y = fake_na.loc[fake_na.index.difference(splits.val_y.index)] -# splits # %% splits.test_y @@ -684,14 +706,14 @@ def join_as_str(seq): # per feature are allowd. diff = (splits - .val_y - .index - .levels[-1] - .difference(splits - .train_X - .index - .levels[-1] - ).to_list()) + .val_y + .index + .levels[-1] + .difference(splits + .train_X + .index + .levels[-1] + ).to_list()) if diff: to_remove = splits.val_y.loc[pd.IndexSlice[:, diff]] display(to_remove) @@ -701,14 +723,14 @@ def join_as_str(seq): # %% diff = (splits - .test_y - .index - .levels[-1] - .difference(splits - .train_X - .index - .levels[-1] - ).to_list()) + .test_y + .index + .levels[-1] + .difference(splits + .train_X + .index + .levels[-1] + ).to_list()) if diff: to_remove = splits.test_y.loc[pd.IndexSlice[:, diff]] display(to_remove) @@ -744,7 +766,7 @@ def join_as_str(seq): splits_df['val'] = splits.val_y splits_df['test'] = splits.test_y stats_splits = splits_df.describe() -stats_splits.to_excel(writer, 'stats_splits', float_format='%.2f') +# stats_splits.to_excel(writer, 'stats_splits', float_format='%.2f') stats_splits # %% @@ -767,7 +789,7 @@ def join_as_str(seq): bins=bins, ax=None, color='C0', -)) + )) _ = (splits .val_y .plot @@ -790,7 +812,7 @@ def join_as_str(seq): legend=False, stacked=True, color=['C0', 'C1', 'C2'], - ) + ) ax.legend(_legend) ax.set_xlabel('Intensity bins') ax.yaxis.set_major_formatter("{x:,.0f}") @@ -804,7 +826,7 @@ def join_as_str(seq): color=['C1', 'C2'], legend=False, stacked=True, - ) + ) ax.legend(_legend[1:]) ax.set_xlabel('Intensity bins') ax.yaxis.set_major_formatter("{x:,.0f}") @@ -832,6 +854,31 @@ def join_as_str(seq): figures[fname.stem] = fname vaep.savefig(ax.get_figure(), fname) +# %% +medians = (splits + .train_X + .median() + .astype(int) + ).to_frame('median_floor') + +feat_with_median = medians.groupby('median_floor').size().rename('M feat') +medians = medians.join(feat_with_median, on='median_floor') +medians = medians.apply(lambda s: "{:02,d} (N={:3,d})".format(*s), axis=1) + +fig, ax = plt.subplots(figsize=(8, 2)) +s = 1 +s_axes = pd.DataFrame({'medians': medians, + 'validation split': splits.val_y.notna().sum(), + 'training split': splits.train_X.notna().sum()} + ).plot.box(by='medians', + subplots=True, + boxprops=dict(linewidth=s), + flierprops=dict(markersize=s), + ax=ax) +for ax in s_axes: + _ = ax.set_xticklabels(ax.get_xticklabels(), + rotation=45, + horizontalalignment='right') # %% [markdown] # ## Save parameters diff --git a/vaep/plotting/data.py b/vaep/plotting/data.py index 1fbd31d7a..f50c63606 100644 --- a/vaep/plotting/data.py +++ b/vaep/plotting/data.py @@ -1,4 +1,4 @@ -"""Plot data distribution based on pandas DataFrames or Series.""" +"""Plot data distribution based on pandas `DataFrames` or `Series`.""" from typing import Tuple, Iterable import matplotlib @@ -9,7 +9,19 @@ def min_max(s: pd.Series) -> Tuple[int]: - min_bin, max_bin = (int(s.min()), (int(s.max())+1)) + """Get the min and max as integer from a pandas.Series. + + Parameters + ---------- + s : pd.Series + Series of intensities. + + Returns + ------- + Tuple[int] + _description_ + """ + min_bin, max_bin = (int(s.min()), (int(s.max()) + 1)) return min_bin, max_bin @@ -27,10 +39,10 @@ def get_min_max_iterable(series: Iterable[pd.Series]) -> Tuple[int]: def plot_histogram_intensities(s: pd.Series, - interval_bins=1, - min_max=(15, 40), - ax=None, - **kwargs) -> Tuple[Axes, range]: + interval_bins=1, + min_max=(15, 40), + ax=None, + **kwargs) -> Tuple[Axes, range]: """Plot intensities in Series in a certain range and equally spaced intervals.""" min_bin, max_bin = min_max bins = range(min_bin, max_bin, interval_bins) @@ -90,8 +102,24 @@ def plot_observations(df: pd.DataFrame, def plot_missing_dist_highdim(data: pd.DataFrame, - min_feat_per_sample=None, - min_samples_per_feat=None) -> matplotlib.figure.Figure: + min_feat_per_sample: int = None, + min_samples_per_feat: int = None) -> matplotlib.figure.Figure: + """Plot missing distribution (cdf) in high dimensional data. + + Parameters + ---------- + data : pd.DataFrame + Intensity table with samples in rows and features in columns. + min_feat_per_sample : int, optional + Show the minimum required features a sample has to have, by default None + min_samples_per_feat : int, optional + Show the minimum required number of samples a feature has to be found in, by default None + + Returns + ------- + matplotlib.figure.Figure + Figure with two plots (Axes). + """ fig, axes = plt.subplots(1, 2, figsize=(4, 2)) not_na = data.notna() name = 'features per sample' @@ -251,8 +279,8 @@ def plot_feat_median_over_prop_missing(data: pd.DataFrame, missing_by_median['bins'] = pd.cut( missing_by_median['median feat value'], bins=bins) missing_by_median['median feat value (floor)'] = (missing_by_median['median feat value'] - .astype(int) - ) + .astype(int) + ) _counts = (missing_by_median .groupby('median feat value (floor)')['median feat value'] .count() From ac66abcdba1b4f5c070992c33b10c7b34204fd24 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 18 Sep 2023 10:40:48 +0200 Subject: [PATCH 04/70] :bug: regression: use filtered dataset - refactoring error -> select correct data --- project/01_0_split_data.ipynb | 46 ++++++++++++++++++----------------- project/01_0_split_data.py | 46 ++++++++++++++++++----------------- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/project/01_0_split_data.ipynb b/project/01_0_split_data.ipynb index 5d0214392..7ec02d1d6 100644 --- a/project/01_0_split_data.ipynb +++ b/project/01_0_split_data.ipynb @@ -200,6 +200,7 @@ "analysis.log_transform(log_fct)\n", "logger.info(f\"{analysis = }\")\n", "df = analysis.df\n", + "del analysis.df # free memory\n", "df" ] }, @@ -681,6 +682,7 @@ "source": [ "K = 2\n", "df = df.astype(float)\n", + "analysis.df = df\n", "pcs = analysis.get_PCA(n_components=K) # should be renamed to get_PCs\n", "pcs = pcs.iloc[:, :K].join(df_meta).join(sample_counts)\n", "\n", @@ -969,10 +971,9 @@ }, "outputs": [], "source": [ - "analysis.splits = DataSplits(is_wide_format=False)\n", - "splits = analysis.splits\n", - "print(f\"{analysis.splits = }\")\n", - "analysis.splits.__annotations__" + "splits = DataSplits(is_wide_format=False)\n", + "print(f\"{splits = }\")\n", + "splits.__annotations__" ] }, { @@ -989,8 +990,8 @@ "metadata": {}, "outputs": [], "source": [ - "analysis.to_long_format(inplace=True)\n", - "analysis.df_long" + "df_long = vaep.io.datasplits.long_format(df)\n", + "df_long.head()" ] }, { @@ -1000,22 +1001,22 @@ "outputs": [], "source": [ "# if not mnar:\n", - "# fake_na, splits.train_X = sample_data(analysis.df_long.squeeze(),\n", + "# fake_na, splits.train_X = sample_data(df_long.squeeze(),\n", "# sample_index_to_drop=0,\n", - "# # weights=freq_per_feature,\n", + "# weights=freq_per_feature,\n", "# frac=0.1,\n", "# random_state=params.random_state,)\n", "# assert len(splits.train_X) > len(fake_na)\n", "! move parameter checks to start of script\n", "if 0.0 <= params.frac_mnar <= 1.0:\n", " fig, axes = plt.subplots(1, 2, figsize=(8, 2))\n", - " quantile_frac = analysis.df_long.quantile(params.frac_non_train)\n", + " quantile_frac = df_long.quantile(params.frac_non_train)\n", " rng = np.random.default_rng(params.random_state)\n", " threshold = pd.Series(rng.normal(loc=float(quantile_frac),\n", - " scale=float(0.3 * analysis.df_long.std()),\n", - " size=len(analysis.df_long),\n", + " scale=float(0.3 * df_long.std()),\n", + " size=len(df_long),\n", " ),\n", - " index=analysis.df_long.index,\n", + " index=df_long.index,\n", " )\n", " # plot data vs threshold data\n", " ax = axes[0]\n", @@ -1024,7 +1025,7 @@ " min_max=min_max,\n", " alpha=0.8)\n", " plot_histogram_intensities(\n", - " analysis.df_long.squeeze(),\n", + " df_long.squeeze(),\n", " ax=ax,\n", " label='observed')\n", " plot_histogram_intensities(\n", @@ -1033,17 +1034,17 @@ " label='thresholds')\n", " ax.legend()\n", " # select MNAR (intensity between randomly sampled threshold)\n", - " mask = analysis.df_long.squeeze() < threshold\n", + " mask = df_long.squeeze() < threshold\n", " ! subsample to have exact fraction of MNAR?\n", - " N = len(analysis.df_long)\n", + " N = len(df_long)\n", " logger.info(f\"{int(N * params.frac_non_train) = :,d}\")\n", " N_MNAR = int(params.frac_non_train * params.frac_mnar * N)\n", - " fake_na_mnar = analysis.df_long.loc[mask]\n", + " fake_na_mnar = df_long.loc[mask]\n", " if len(fake_na_mnar) > N_MNAR:\n", " fake_na_mnar = fake_na_mnar.sample(N_MNAR,\n", " random_state=params.random_state)\n", - " splits.train_X = analysis.df_long.loc[\n", - " analysis.df_long.index.difference(\n", + " splits.train_X = df_long.loc[\n", + " df_long.index.difference(\n", " fake_na_mnar.index)\n", " ]\n", " logger.info(f\"{len(fake_na_mnar) = :,d}\")\n", @@ -1074,7 +1075,7 @@ " color='C3',\n", " label=f'MCAR ({N_MCAR:,d})')\n", " ax.legend()\n", - " assert len(fake_na) + len(splits.train_X) == len(analysis.df_long)\n", + " assert len(fake_na) + len(splits.train_X) == len(df_long)\n", "else:\n", " raise ValueError(f\"Invalid MNAR float value (should be betw. 0 and 1): {params.frac_mnar}\")\n", "\n", @@ -1088,7 +1089,7 @@ "metadata": {}, "outputs": [], "source": [ - "splits.test_y" + "splits.test_y.groupby(level=-1).count().describe()" ] }, { @@ -1106,7 +1107,8 @@ "metadata": {}, "outputs": [], "source": [ - "splits.train_X" + "! add option to retain at least N samples per feature\n", + "splits.train_X.groupby(level=-1).count().describe()" ] }, { @@ -1214,7 +1216,7 @@ "metadata": {}, "outputs": [], "source": [ - "splits_df = pd.DataFrame(index=analysis.df_long.index)\n", + "splits_df = pd.DataFrame(index=df_long.index)\n", "splits_df['train'] = splits.train_X\n", "splits_df['val'] = splits.val_y\n", "splits_df['test'] = splits.test_y\n", diff --git a/project/01_0_split_data.py b/project/01_0_split_data.py index 9507aeb39..87b745709 100644 --- a/project/01_0_split_data.py +++ b/project/01_0_split_data.py @@ -145,6 +145,7 @@ def add_meta_data(df: pd.DataFrame, df_meta: pd.DataFrame): analysis.log_transform(log_fct) logger.info(f"{analysis = }") df = analysis.df +del analysis.df # free memory df # %% @@ -424,6 +425,7 @@ def join_as_str(seq): # %% K = 2 df = df.astype(float) +analysis.df = df pcs = analysis.get_PCA(n_components=K) # should be renamed to get_PCs pcs = pcs.iloc[:, :K].join(df_meta).join(sample_counts) @@ -592,10 +594,9 @@ def join_as_str(seq): # - select frac_mnar from intensities selected using threshold matrix # %% -analysis.splits = DataSplits(is_wide_format=False) -splits = analysis.splits -print(f"{analysis.splits = }") -analysis.splits.__annotations__ +splits = DataSplits(is_wide_format=False) +print(f"{splits = }") +splits.__annotations__ # %% [markdown] @@ -603,27 +604,27 @@ def join_as_str(seq): # Simulated missing values are not used for validation and testing. # %% -analysis.to_long_format(inplace=True) -analysis.df_long +df_long = vaep.io.datasplits.long_format(df) +df_long.head() # %% # if not mnar: -# fake_na, splits.train_X = sample_data(analysis.df_long.squeeze(), +# fake_na, splits.train_X = sample_data(df_long.squeeze(), # sample_index_to_drop=0, -# # weights=freq_per_feature, +# weights=freq_per_feature, # frac=0.1, # random_state=params.random_state,) # assert len(splits.train_X) > len(fake_na) # ! move parameter checks to start of script if 0.0 <= params.frac_mnar <= 1.0: fig, axes = plt.subplots(1, 2, figsize=(8, 2)) - quantile_frac = analysis.df_long.quantile(params.frac_non_train) + quantile_frac = df_long.quantile(params.frac_non_train) rng = np.random.default_rng(params.random_state) threshold = pd.Series(rng.normal(loc=float(quantile_frac), - scale=float(0.3 * analysis.df_long.std()), - size=len(analysis.df_long), + scale=float(0.3 * df_long.std()), + size=len(df_long), ), - index=analysis.df_long.index, + index=df_long.index, ) # plot data vs threshold data ax = axes[0] @@ -632,7 +633,7 @@ def join_as_str(seq): min_max=min_max, alpha=0.8) plot_histogram_intensities( - analysis.df_long.squeeze(), + df_long.squeeze(), ax=ax, label='observed') plot_histogram_intensities( @@ -641,17 +642,17 @@ def join_as_str(seq): label='thresholds') ax.legend() # select MNAR (intensity between randomly sampled threshold) - mask = analysis.df_long.squeeze() < threshold + mask = df_long.squeeze() < threshold # ! subsample to have exact fraction of MNAR? - N = len(analysis.df_long) + N = len(df_long) logger.info(f"{int(N * params.frac_non_train) = :,d}") N_MNAR = int(params.frac_non_train * params.frac_mnar * N) - fake_na_mnar = analysis.df_long.loc[mask] + fake_na_mnar = df_long.loc[mask] if len(fake_na_mnar) > N_MNAR: fake_na_mnar = fake_na_mnar.sample(N_MNAR, random_state=params.random_state) - splits.train_X = analysis.df_long.loc[ - analysis.df_long.index.difference( + splits.train_X = df_long.loc[ + df_long.index.difference( fake_na_mnar.index) ] logger.info(f"{len(fake_na_mnar) = :,d}") @@ -682,7 +683,7 @@ def join_as_str(seq): color='C3', label=f'MCAR ({N_MCAR:,d})') ax.legend() - assert len(fake_na) + len(splits.train_X) == len(analysis.df_long) + assert len(fake_na) + len(splits.train_X) == len(df_long) else: raise ValueError(f"Invalid MNAR float value (should be betw. 0 and 1): {params.frac_mnar}") @@ -690,13 +691,14 @@ def join_as_str(seq): splits.test_y = fake_na.loc[fake_na.index.difference(splits.val_y.index)] # %% -splits.test_y +splits.test_y.groupby(level=-1).count().describe() # %% splits.val_y # %% -splits.train_X +# ! add option to retain at least N samples per feature +splits.train_X.groupby(level=-1).count().describe() # %% # ToDo check that feature indices and sample indicies overlap @@ -761,7 +763,7 @@ def join_as_str(seq): # ## plot distribution of splits # %% -splits_df = pd.DataFrame(index=analysis.df_long.index) +splits_df = pd.DataFrame(index=df_long.index) splits_df['train'] = splits.train_X splits_df['val'] = splits.val_y splits_df['test'] = splits.test_y From a2b97b878363e7f096a43bff602aa460d25b1358 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 18 Sep 2023 10:43:33 +0200 Subject: [PATCH 05/70] :zap: CICD pipeline: some R methods are slow - only test CF, DAE and VAE functionally - select configs in example folder... --- project/config/single_dev_dataset/example/config.yaml | 8 ++++---- project/config/single_dev_dataset/example/train_CF.yaml | 6 +++--- project/config/single_dev_dataset/example/train_DAE.yaml | 4 ++-- project/config/single_dev_dataset/example/train_VAE.yaml | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/project/config/single_dev_dataset/example/config.yaml b/project/config/single_dev_dataset/example/config.yaml index b7ed7f717..0181d36ed 100644 --- a/project/config/single_dev_dataset/example/config.yaml +++ b/project/config/single_dev_dataset/example/config.yaml @@ -1,5 +1,5 @@ -config_split: config/single_dev_dataset/proteinGroups_N50/split.yaml -config_train: config/single_dev_dataset/proteinGroups_N50/train_{model}.yaml +config_split: config/single_dev_dataset/example/split.yaml +config_train: config/single_dev_dataset/example/train_{model}.yaml folder_experiment: runs/example # folder_experiment: runs/dev_dataset_small/proteinGroups_N50 fn_rawfile_metadata: data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv @@ -14,10 +14,10 @@ NAGuideR_methods: - ROWMEDIAN # e1071 - KNN_IMPUTE # impute - SEQKNN # SeqKNN - - RF # missForest + - RF # missForest - ~7mins - IMPSEQ # rrcovNA - QRILC # imputeLCMD - SVDMETHOD # pcaMethods - MICE-NORM # mice - MLE # norm - - IRM # VIM + - IRM # VIM - ~9mins diff --git a/project/config/single_dev_dataset/example/train_CF.yaml b/project/config/single_dev_dataset/example/train_CF.yaml index 30f22595c..751cd8ef9 100644 --- a/project/config/single_dev_dataset/example/train_CF.yaml +++ b/project/config/single_dev_dataset/example/train_CF.yaml @@ -1,8 +1,8 @@ -folder_experiment: runs/example +folder_experiment: runs/example file_format: csv latent_dim: 50 batch_size: 4096 -epochs_max: 20 +epochs_max: 3 sample_idx_position: 0 cuda: False -save_pred_real_na: True \ No newline at end of file +save_pred_real_na: True diff --git a/project/config/single_dev_dataset/example/train_DAE.yaml b/project/config/single_dev_dataset/example/train_DAE.yaml index d01114dad..6fa4e5e3e 100644 --- a/project/config/single_dev_dataset/example/train_DAE.yaml +++ b/project/config/single_dev_dataset/example/train_DAE.yaml @@ -1,8 +1,8 @@ file_format: csv latent_dim: 10 batch_size: 10 -epochs_max: 100 +epochs_max: 5 hidden_layers: "512" sample_idx_position: 0 cuda: False -save_pred_real_na: True \ No newline at end of file +save_pred_real_na: True diff --git a/project/config/single_dev_dataset/example/train_VAE.yaml b/project/config/single_dev_dataset/example/train_VAE.yaml index 993649f5d..72a4e6c52 100644 --- a/project/config/single_dev_dataset/example/train_VAE.yaml +++ b/project/config/single_dev_dataset/example/train_VAE.yaml @@ -1,10 +1,10 @@ # models_training: -folder_experiment: runs/example +folder_experiment: runs/example file_format: csv latent_dim: 25 batch_size: 10 -epochs_max: 50 +epochs_max: 5 hidden_layers: "512_256" sample_idx_position: 0 cuda: False -save_pred_real_na: True \ No newline at end of file +save_pred_real_na: True From 13dba85c515a5fed0f7afa0d53c3ff9f03e9f630 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 18 Sep 2023 12:30:51 +0200 Subject: [PATCH 06/70] :art: format all code using autopep8 - both scripts (notebooks) - and library code --- project/00_0_0_lftp_upload_commands.ipynb | 65 +- project/00_0_0_lftp_upload_commands.py | 62 +- project/00_0_1_check_filesizes.ipynb | 22 +- project/00_0_1_check_filesizes.py | 19 +- project/00_0_2_mqout_renaming.ipynb | 16 +- project/00_0_2_mqout_renaming.py | 16 +- project/00_0_3_create_sdrf.ipynb | 2 +- project/00_0_3_create_sdrf.py | 2 +- project/00_0_4_create_submission_folder.ipynb | 8 +- project/00_0_4_create_submission_folder.py | 5 +- project/00_0_hela_metadata_rawfiles.ipynb | 6 +- project/00_0_hela_metadata_rawfiles.py | 6 +- project/00_1_hela_MQ_summaries.ipynb | 25 +- project/00_1_hela_MQ_summaries.py | 24 +- project/00_2_hela_all_raw_files.ipynb | 43 +- project/00_2_hela_all_raw_files.py | 45 +- project/00_3_0_pride_metadata_creation.ipynb | 25 +- project/00_3_0_pride_metadata_creation.py | 27 +- project/00_3_1_pride_metadata_analysis.ipynb | 98 +- project/00_3_1_pride_metadata_analysis.py | 96 +- project/00_4_development_dataset_support.py | 9 +- ...4_hela_development_dataset_splitting.ipynb | 36 +- ...00_4_hela_development_dataset_splitting.py | 38 +- project/00_6_0_permute_data.ipynb | 35 +- project/00_6_0_permute_data.py | 33 +- .../00_6_hela_training_data_exploration.ipynb | 929 ++++++++++-------- .../00_6_hela_training_data_exploration.py | 51 +- .../01_0_transform_data_to_wide_format.ipynb | 11 +- project/01_0_transform_data_to_wide_format.py | 7 +- project/01_1_train_CF.ipynb | 43 +- project/01_1_train_CF.py | 36 +- project/01_1_train_DAE.ipynb | 33 +- project/01_1_train_DAE.py | 35 +- project/01_1_train_Median.ipynb | 63 +- project/01_1_train_Median.py | 59 +- project/01_1_train_RSN.ipynb | 8 +- project/01_1_train_RSN.py | 10 +- project/01_1_train_VAE.ipynb | 34 +- project/01_1_train_VAE.py | 34 +- project/01_1_transfer_NAGuideR_pred.py | 2 +- project/02_1_aggregate_metrics.py.py | 2 +- project/02_1_join_metrics.py.ipynb | 8 +- project/02_1_join_metrics.py.py | 6 +- project/02_2_aggregate_configs.py.ipynb | 6 +- project/02_2_aggregate_configs.py.py | 8 +- project/02_2_join_configs.py.ipynb | 2 +- project/02_2_join_configs.py.py | 2 +- project/02_3_grid_search_analysis.ipynb | 131 +-- project/02_3_grid_search_analysis.py | 129 +-- project/02_4_best_models_over_all_data.ipynb | 99 +- project/02_4_best_models_over_all_data.py | 101 +- project/03_1_best_models_comparison.ipynb | 4 +- project/03_1_best_models_comparison.py | 6 +- project/03_2_best_models_comparison_fig2.py | 2 +- ...3_3_combine_experiment_result_tables.ipynb | 12 +- .../03_3_combine_experiment_result_tables.py | 12 +- project/03_4_join_tables.py | 18 +- project/03_5_join_benchmarks.py | 7 +- project/04_1_train_pimms_models.ipynb | 86 +- project/04_1_train_pimms_models.py | 86 +- project/10_0_ald_data.ipynb | 103 +- project/10_0_ald_data.py | 105 +- project/10_0_ald_data_3v3.py | 31 + project/10_1_ald_diff_analysis.ipynb | 57 +- project/10_1_ald_diff_analysis.py | 59 +- project/10_2_ald_compare_methods.ipynb | 47 +- project/10_2_ald_compare_methods.py | 43 +- project/10_3_ald_ml_new_feat.ipynb | 12 +- project/10_3_ald_ml_new_feat.py | 14 +- project/10_4_ald_compare_single_pg.ipynb | 14 +- project/10_4_ald_compare_single_pg.py | 16 +- .../10_5_comp_diff_analysis_repetitions.ipynb | 54 +- .../10_5_comp_diff_analysis_repetitions.py | 52 +- project/10_6_interpret_repeated_ald_da.py | 6 +- project/10_7_ald_reduced_dataset_plots.ipynb | 36 +- project/10_7_ald_reduced_dataset_plots.py | 31 +- project/erda_00_maxquant_file_reader.ipynb | 25 +- project/erda_00_maxquant_file_reader.py | 27 +- project/erda_01_mq_select_runs.ipynb | 97 +- project/erda_01_mq_select_runs.py | 99 +- project/erda_02_mq_count_features.ipynb | 113 +-- project/erda_02_mq_count_features.py | 112 +-- project/erda_03_training_data.ipynb | 42 +- project/erda_03_training_data.py | 33 +- project/erda_04_transpose_file.ipynb | 12 +- project/erda_04_transpose_file.py | 14 +- project/erda_05_parse_paramter_files.ipynb | 8 +- project/erda_05_parse_paramter_files.py | 2 +- project/erda_12_explore_raw_MQ_data.ipynb | 82 +- project/erda_12_explore_raw_MQ_data.py | 83 +- project/erda_data_available.ipynb | 12 +- project/erda_data_available.py | 14 +- project/misc_FASTA_data_agg_by_gene.ipynb | 19 +- project/misc_FASTA_data_agg_by_gene.py | 21 +- project/misc_FASTA_tryptic_digest.ipynb | 76 +- project/misc_FASTA_tryptic_digest.py | 76 +- project/misc_id_mapper.py | 458 +++++++++ project/misc_illustrations.ipynb | 41 +- project/misc_illustrations.py | 43 +- vaep/analyzers/__init__.py | 5 +- vaep/analyzers/analyzers.py | 75 +- vaep/analyzers/compare_predictions.py | 6 +- vaep/analyzers/diff_analysis.py | 4 +- vaep/analyzers/metadata.py | 2 +- vaep/databases/__init__.py | 1 - vaep/databases/diseases.py | 7 +- vaep/databases/uniprot.py | 8 +- vaep/io/__init__.py | 17 +- vaep/io/data_objects.py | 85 +- vaep/io/dataloaders.py | 9 +- vaep/io/datasets.py | 25 +- vaep/io/datasplits.py | 35 +- vaep/io/filenames.py | 4 +- vaep/io/format.py | 2 +- vaep/io/mq.py | 18 +- vaep/io/rawfiles.py | 16 +- vaep/io/thermo_raw_files.py | 1 - vaep/io/types.py | 6 +- vaep/model.py | 23 +- vaep/models/__init__.py | 28 +- vaep/models/ae.py | 74 +- vaep/models/analysis.py | 5 +- vaep/models/cmd.py | 8 +- vaep/models/collab.py | 35 +- vaep/models/collect_dumps.py | 2 +- vaep/models/vae.py | 23 +- vaep/nb.py | 14 +- vaep/pandas/__init__.py | 30 +- vaep/pandas/missing_data.py | 4 +- vaep/plotting/__init__.py | 40 +- vaep/sampling.py | 8 +- vaep/stats/__init__.py | 2 +- vaep/stats/diff_analysis.py | 8 +- vaep/tests/io/test_data_objects.py | 2 +- vaep/tests/io/test_dataloaders.py | 8 +- vaep/tests/io/test_dataset.py | 5 +- vaep/tests/io/test_datasplits.py | 21 +- .../models/__pycache__/test_collect_dumps.py | 4 - vaep/tests/pandas/test_calc_errors.py | 4 +- vaep/tests/test_ae.py | 4 +- vaep/tests/test_collab.py | 11 +- vaep/tests/test_helpers.py | 4 +- vaep/tests/test_imputation.py | 19 +- vaep/tests/test_io.py | 11 +- vaep/tests/test_nb.py | 2 +- vaep/tests/test_pandas.py | 25 +- vaep/tests/test_transfrom.py | 17 +- vaep/tf_board.py | 7 +- vaep/transform.py | 18 +- vaep/utils.py | 16 +- 150 files changed, 3363 insertions(+), 2479 deletions(-) create mode 100644 project/10_0_ald_data_3v3.py create mode 100644 project/misc_id_mapper.py diff --git a/project/00_0_0_lftp_upload_commands.ipynb b/project/00_0_0_lftp_upload_commands.ipynb index 81dd8c796..1d9ae4337 100644 --- a/project/00_0_0_lftp_upload_commands.ipynb +++ b/project/00_0_0_lftp_upload_commands.ipynb @@ -56,11 +56,11 @@ }, "outputs": [], "source": [ - "fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' # Machine parsed metadata from rawfile workflow\n", - "fn_mq_summaries: str = 'data/samples_selected_summaries.csv' # MaxQuant summary files\n", - "fn_files_selected: str = 'data/samples_selected.yaml' # selected files based on threshold of identified peptides\n", - "out_folder: str = 'data/rename' # output folder\n", - "fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files" + "fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' # Machine parsed metadata from rawfile workflow\n", + "fn_mq_summaries: str = 'data/samples_selected_summaries.csv' # MaxQuant summary files\n", + "fn_files_selected: str = 'data/samples_selected.yaml' # selected files based on threshold of identified peptides\n", + "out_folder: str = 'data/rename' # output folder\n", + "fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files" ] }, { @@ -133,14 +133,14 @@ "outputs": [], "source": [ "cols_identifies = [('FileProperties', 'Pathname'),\n", - " ('FileProperties', 'Version'),\n", - " ('FileProperties', 'Content Creation Date'),\n", - " ('InstrumentProperties', 'Thermo Scientific instrument model'),\n", - " ('InstrumentProperties', 'instrument attribute'),\n", - " ('InstrumentProperties', 'instrument serial number'),\n", - " ('InstrumentProperties', 'Software Version'),\n", - " ('InstrumentProperties', 'firmware version'),\n", - "]\n", + " ('FileProperties', 'Version'),\n", + " ('FileProperties', 'Content Creation Date'),\n", + " ('InstrumentProperties', 'Thermo Scientific instrument model'),\n", + " ('InstrumentProperties', 'instrument attribute'),\n", + " ('InstrumentProperties', 'instrument serial number'),\n", + " ('InstrumentProperties', 'Software Version'),\n", + " ('InstrumentProperties', 'firmware version'),\n", + " ]\n", "\n", "df_meta = df_meta[cols_identifies]\n", "df_meta.columns = [t[-1] for t in cols_identifies]\n", @@ -198,9 +198,9 @@ "source": [ "date_col = \"Content Creation Date\"\n", "idx_all = (pd.to_datetime(df_meta[date_col]).dt.strftime(\"%Y_%m_%d_%H_%M\")\n", - " + '_'\n", - " + df_meta[\"Instrument_name\"]\n", - ").str.replace(' ', '-')\n", + " + '_'\n", + " + df_meta[\"Instrument_name\"]\n", + " ).str.replace(' ', '-')\n", "\n", "mask = idx_all.duplicated(keep=False)\n", "duplicated_sample_idx = idx_all.loc[mask].sort_values() # duplicated dumps\n", @@ -214,8 +214,7 @@ "metadata": {}, "outputs": [], "source": [ - "df_meta['new_sample_id'] = idx_all\n", - "\n", + "df_meta['new_sample_id'] = idx_all\n", "\n", "\n", "_n = df_meta.groupby(\"new_sample_id\").cumcount().astype('string').str.replace('0', '')\n", @@ -340,10 +339,10 @@ " if string_ not in used_before:\n", " ret += f'_{string_}'\n", " used_before |= set(strings_)\n", - " ret = (ret[1:] # remove _ from start\n", + " ret = (ret[1:] # remove _ from start\n", " .replace('Slot_#', '')\n", " .replace('slot_#', '')\n", - " )\n", + " )\n", " return ret\n", "\n", "\n", @@ -353,7 +352,7 @@ " \"instrument attribute\",\n", " \"instrument serial number\",\n", " ]\n", - " ]\n", + "]\n", " .sample(20)\n", " .apply(build_instrument_name, axis=1)\n", ")" @@ -401,8 +400,8 @@ " .loc[selected, \"Path_old\"]\n", " .iloc[:3]\n", " .to_csv(out_folder / 'rawfiles_to_checksum.txt',\n", - " index=False,\n", - " header=False)\n", + " index=False,\n", + " header=False)\n", " )" ] }, @@ -453,7 +452,7 @@ "```\n", "to allow parallell commands, use the runtime setting\n", "```bash\n", - ">>> cat ~/.lftprc \n", + ">>> cat ~/.lftprc\n", "set cmd:parallel 2\n", "```" ] @@ -501,11 +500,11 @@ "source": [ "commands = df_meta.loc[selected]\n", "commands = (\n", - " 'put ' \n", + " 'put '\n", " + commands['Path_old'].astype('string')\n", - " + ' -o ' \n", - " + \"./raw_files/\" \n", - " + commands[\"Instrument_name\"] \n", + " + ' -o '\n", + " + \"./raw_files/\"\n", + " + commands[\"Instrument_name\"]\n", " + '/'\n", " + commands['new_sample_id'] + '.raw'\n", ")\n", @@ -559,9 +558,9 @@ "source": [ "commands = df_meta.loc[selected]\n", "commands = (\n", - " \"mirror -R --only-missing --log log_lftp_mirror.log --exclude-glob *.pdf \" # command\n", - " + \"mq_out/\" + commands.index # source\n", - " + \" ./MQ_tables/\" + commands[\"Instrument_name\"]+ \"/\" + commands[\"new_sample_id\"] # dest\n", + " \"mirror -R --only-missing --log log_lftp_mirror.log --exclude-glob *.pdf \" # command\n", + " + \"mq_out/\" + commands.index # source\n", + " + \" ./MQ_tables/\" + commands[\"Instrument_name\"] + \"/\" + commands[\"new_sample_id\"] # dest\n", ")\n", "\n", "print(commands.sample(10).to_csv(header=False, index=False))" @@ -579,9 +578,7 @@ "cell_type": "code", "execution_count": null, "id": "83c04b90-0c4e-4fe7-88f6-ed02cef93a23", - "metadata": { - "lines_to_next_cell": 2 - }, + "metadata": {}, "outputs": [], "source": [ "fname = out_folder / 'lftp_commands_mq_output.txt'\n", diff --git a/project/00_0_0_lftp_upload_commands.py b/project/00_0_0_lftp_upload_commands.py index 921a5733f..17cc26be2 100644 --- a/project/00_0_0_lftp_upload_commands.py +++ b/project/00_0_0_lftp_upload_commands.py @@ -42,11 +42,11 @@ def rename(fname, new_sample_id, new_folder=None, ext=None): # ## Arguments # %% tags=["parameters"] -fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' # Machine parsed metadata from rawfile workflow -fn_mq_summaries: str = 'data/samples_selected_summaries.csv' # MaxQuant summary files -fn_files_selected: str = 'data/samples_selected.yaml' # selected files based on threshold of identified peptides -out_folder: str = 'data/rename' # output folder -fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files +fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' # Machine parsed metadata from rawfile workflow +fn_mq_summaries: str = 'data/samples_selected_summaries.csv' # MaxQuant summary files +fn_files_selected: str = 'data/samples_selected.yaml' # selected files based on threshold of identified peptides +out_folder: str = 'data/rename' # output folder +fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files # %% out_folder = Path(out_folder) @@ -79,14 +79,14 @@ def rename(fname, new_sample_id, new_folder=None, ext=None): # %% cols_identifies = [('FileProperties', 'Pathname'), - ('FileProperties', 'Version'), - ('FileProperties', 'Content Creation Date'), - ('InstrumentProperties', 'Thermo Scientific instrument model'), - ('InstrumentProperties', 'instrument attribute'), - ('InstrumentProperties', 'instrument serial number'), - ('InstrumentProperties', 'Software Version'), - ('InstrumentProperties', 'firmware version'), -] + ('FileProperties', 'Version'), + ('FileProperties', 'Content Creation Date'), + ('InstrumentProperties', 'Thermo Scientific instrument model'), + ('InstrumentProperties', 'instrument attribute'), + ('InstrumentProperties', 'instrument serial number'), + ('InstrumentProperties', 'Software Version'), + ('InstrumentProperties', 'firmware version'), + ] df_meta = df_meta[cols_identifies] df_meta.columns = [t[-1] for t in cols_identifies] @@ -113,17 +113,16 @@ def rename(fname, new_sample_id, new_folder=None, ext=None): # %% date_col = "Content Creation Date" idx_all = (pd.to_datetime(df_meta[date_col]).dt.strftime("%Y_%m_%d_%H_%M") - + '_' - + df_meta["Instrument_name"] -).str.replace(' ', '-') + + '_' + + df_meta["Instrument_name"] + ).str.replace(' ', '-') mask = idx_all.duplicated(keep=False) duplicated_sample_idx = idx_all.loc[mask].sort_values() # duplicated dumps duplicated_sample_idx # %% -df_meta['new_sample_id'] = idx_all - +df_meta['new_sample_id'] = idx_all _n = df_meta.groupby("new_sample_id").cumcount().astype('string').str.replace('0', '') @@ -182,10 +181,10 @@ def build_instrument_name(s): if string_ not in used_before: ret += f'_{string_}' used_before |= set(strings_) - ret = (ret[1:] # remove _ from start + ret = (ret[1:] # remove _ from start .replace('Slot_#', '') .replace('slot_#', '') - ) + ) return ret @@ -195,7 +194,7 @@ def build_instrument_name(s): "instrument attribute", "instrument serial number", ] - ] +] .sample(20) .apply(build_instrument_name, axis=1) ) @@ -217,8 +216,8 @@ def build_instrument_name(s): .loc[selected, "Path_old"] .iloc[:3] .to_csv(out_folder / 'rawfiles_to_checksum.txt', - index=False, - header=False) + index=False, + header=False) ) # %% [markdown] @@ -247,7 +246,7 @@ def build_instrument_name(s): # ``` # to allow parallell commands, use the runtime setting # ```bash -# >>> cat ~/.lftprc +# >>> cat ~/.lftprc # set cmd:parallel 2 # ``` @@ -269,11 +268,11 @@ def build_instrument_name(s): # %% commands = df_meta.loc[selected] commands = ( - 'put ' + 'put ' + commands['Path_old'].astype('string') - + ' -o ' - + "./raw_files/" - + commands["Instrument_name"] + + ' -o ' + + "./raw_files/" + + commands["Instrument_name"] + '/' + commands['new_sample_id'] + '.raw' ) @@ -299,9 +298,9 @@ def build_instrument_name(s): # %% commands = df_meta.loc[selected] commands = ( - "mirror -R --only-missing --log log_lftp_mirror.log --exclude-glob *.pdf " # command - + "mq_out/" + commands.index # source - + " ./MQ_tables/" + commands["Instrument_name"]+ "/" + commands["new_sample_id"] # dest + "mirror -R --only-missing --log log_lftp_mirror.log --exclude-glob *.pdf " # command + + "mq_out/" + commands.index # source + + " ./MQ_tables/" + commands["Instrument_name"] + "/" + commands["new_sample_id"] # dest ) print(commands.sample(10).to_csv(header=False, index=False)) @@ -312,4 +311,3 @@ def build_instrument_name(s): # %% fname = out_folder / 'lftp_commands_mq_output.txt' commands.to_csv(fname, header=False, index=False) - diff --git a/project/00_0_1_check_filesizes.ipynb b/project/00_0_1_check_filesizes.ipynb index 36b937a6b..549a0b1ef 100644 --- a/project/00_0_1_check_filesizes.ipynb +++ b/project/00_0_1_check_filesizes.ipynb @@ -153,7 +153,7 @@ "source": [ "mask = (entries['size_pride'] - entries['size_erda']).abs() > 5\n", "to_redo = entries.loc[mask].reset_index()\n", - "to_redo " + "to_redo" ] }, { @@ -172,7 +172,7 @@ "id": "b6087751", "metadata": {}, "source": [ - "## Check MaxQuant output filesizes " + "## Check MaxQuant output filesizes" ] }, { @@ -207,7 +207,7 @@ " files.append(entry)\n", " if entry.id_old not in folder:\n", " folder.add(entry.id_old)\n", - " \n", + "\n", "print(f\"{len(folder) =: }\")\n", "print(f\"{len(files) =: }\")\n", "files[:3]" @@ -235,11 +235,11 @@ "outputs": [], "source": [ "files['path_pride'] = ('MQ_tables/'\n", - " + files['Instrument_name']\n", - " + '/' \n", - " + files[\"new_sample_id\"]\n", - " + '/'\n", - " + files[\"filename\"])\n", + " + files['Instrument_name']\n", + " + '/'\n", + " + files[\"new_sample_id\"]\n", + " + '/'\n", + " + files[\"filename\"])\n", "files['path_pride'].iloc[:4].to_list()" ] }, @@ -250,7 +250,7 @@ "metadata": {}, "outputs": [], "source": [ - "files['filename'].value_counts() # except mqpar.xml all present on erda" + "files['filename'].value_counts() # except mqpar.xml all present on erda" ] }, { @@ -359,9 +359,7 @@ "cell_type": "code", "execution_count": null, "id": "3fc22aef", - "metadata": { - "lines_to_next_cell": 2 - }, + "metadata": {}, "outputs": [], "source": [ "to_do = pd.concat([missing_on_pride, files_redo])\n", diff --git a/project/00_0_1_check_filesizes.py b/project/00_0_1_check_filesizes.py index 64fc10c7f..e8df8a58a 100644 --- a/project/00_0_1_check_filesizes.py +++ b/project/00_0_1_check_filesizes.py @@ -74,14 +74,14 @@ # %% mask = (entries['size_pride'] - entries['size_erda']).abs() > 5 to_redo = entries.loc[mask].reset_index() -to_redo +to_redo # %% commands = 'put ' + to_redo['fname'] + ' -o ' + to_redo['path_pride'] print(commands.to_csv(header=False, index=False)) # %% [markdown] -# ## Check MaxQuant output filesizes +# ## Check MaxQuant output filesizes # %% df_meta = df_meta.reset_index().set_index('Sample ID') @@ -101,7 +101,7 @@ files.append(entry) if entry.id_old not in folder: folder.add(entry.id_old) - + print(f"{len(folder) =: }") print(f"{len(files) =: }") files[:3] @@ -113,16 +113,16 @@ # %% files['path_pride'] = ('MQ_tables/' - + files['Instrument_name'] - + '/' - + files["new_sample_id"] - + '/' - + files["filename"]) + + files['Instrument_name'] + + '/' + + files["new_sample_id"] + + '/' + + files["filename"]) files['path_pride'].iloc[:4].to_list() # %% -files['filename'].value_counts() # except mqpar.xml all present on erda +files['filename'].value_counts() # except mqpar.xml all present on erda # %% files_pride = list() @@ -163,4 +163,3 @@ to_do = pd.concat([missing_on_pride, files_redo]) commands = 'put -e \'' + to_do['path_erda'] + "' -o '" + to_do.index + "'" commands.to_csv(FOLDER / 'mq_out_remaining.txt', header=False, index=False) - diff --git a/project/00_0_2_mqout_renaming.ipynb b/project/00_0_2_mqout_renaming.ipynb index 2f56c1303..e32643f4b 100644 --- a/project/00_0_2_mqout_renaming.ipynb +++ b/project/00_0_2_mqout_renaming.ipynb @@ -36,7 +36,7 @@ "source": [ "FOLDER = Path('data/rename')\n", "meta_in = FOLDER / 'selected_old_new_id_mapping.csv'\n", - "fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files" + "fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files" ] }, { @@ -71,10 +71,10 @@ "outputs": [], "source": [ "files_types = [\"modificationSpecificPeptides.txt\",\n", - "\"mqpar.xml\",\n", - "\"mzRange.txt\",\n", - "\"Oxidation (M)Sites.txt\",\n", - "\"summary.txt\",]" + " \"mqpar.xml\",\n", + " \"mzRange.txt\",\n", + " \"Oxidation (M)Sites.txt\",\n", + " \"summary.txt\",]" ] }, { @@ -109,7 +109,7 @@ " new_name=new_name,\n", " fn=fname)\n", " to_rename.append(command)\n", - " \n", + "\n", " counter[fname.name] += 1\n", "len(to_rename)" ] @@ -122,7 +122,7 @@ "outputs": [], "source": [ "# mqpar.xml missing in some folders\n", - "pd.Series(counter) # maybe one folder has some missing?" + "pd.Series(counter) # maybe one folder has some missing?" ] }, { @@ -133,7 +133,7 @@ "outputs": [], "source": [ "with open(FOLDER / 'sed_rename_commands.sh', 'w') as f:\n", - " f.writelines('\\n'.join(to_rename))" + " f.writelines('\\n'.join(to_rename))" ] } ], diff --git a/project/00_0_2_mqout_renaming.py b/project/00_0_2_mqout_renaming.py index b61e127e9..0a223751f 100644 --- a/project/00_0_2_mqout_renaming.py +++ b/project/00_0_2_mqout_renaming.py @@ -15,7 +15,7 @@ # %% FOLDER = Path('data/rename') meta_in = FOLDER / 'selected_old_new_id_mapping.csv' -fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files +fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files # %% df_meta = pd.read_csv(meta_in, index_col='new_sample_id') @@ -27,10 +27,10 @@ # %% files_types = ["modificationSpecificPeptides.txt", -"mqpar.xml", -"mzRange.txt", -"Oxidation (M)Sites.txt", -"summary.txt",] + "mqpar.xml", + "mzRange.txt", + "Oxidation (M)Sites.txt", + "summary.txt",] # %% name_lookup = df_meta["Sample ID"].reset_index().set_index("new_sample_id") @@ -51,14 +51,14 @@ new_name=new_name, fn=fname) to_rename.append(command) - + counter[fname.name] += 1 len(to_rename) # %% # mqpar.xml missing in some folders -pd.Series(counter) # maybe one folder has some missing? +pd.Series(counter) # maybe one folder has some missing? # %% with open(FOLDER / 'sed_rename_commands.sh', 'w') as f: - f.writelines('\n'.join(to_rename)) + f.writelines('\n'.join(to_rename)) diff --git a/project/00_0_3_create_sdrf.ipynb b/project/00_0_3_create_sdrf.ipynb index e08e3e973..eec8de40d 100644 --- a/project/00_0_3_create_sdrf.ipynb +++ b/project/00_0_3_create_sdrf.ipynb @@ -55,7 +55,7 @@ }, "outputs": [], "source": [ - "sdrf = pd.DataFrame() # pd.read_table(fn_sdrf_cellline_template)\n", + "sdrf = pd.DataFrame() # pd.read_table(fn_sdrf_cellline_template)\n", "sdrf['source name'] = df_meta.index\n", "sdrf = sdrf.set_index('source name')\n", "sdrf['characteristics[organism]'] = 'Homo sapiens'\n", diff --git a/project/00_0_3_create_sdrf.py b/project/00_0_3_create_sdrf.py index 14e033b34..dd6d5178b 100644 --- a/project/00_0_3_create_sdrf.py +++ b/project/00_0_3_create_sdrf.py @@ -17,7 +17,7 @@ df_meta # %% -sdrf = pd.DataFrame() # pd.read_table(fn_sdrf_cellline_template) +sdrf = pd.DataFrame() # pd.read_table(fn_sdrf_cellline_template) sdrf['source name'] = df_meta.index sdrf = sdrf.set_index('source name') sdrf['characteristics[organism]'] = 'Homo sapiens' diff --git a/project/00_0_4_create_submission_folder.ipynb b/project/00_0_4_create_submission_folder.ipynb index 891af6559..59360c84f 100644 --- a/project/00_0_4_create_submission_folder.ipynb +++ b/project/00_0_4_create_submission_folder.ipynb @@ -19,6 +19,8 @@ }, "outputs": [], "source": [ + "import pandas as pd\n", + "import numpy as np\n", "from collections import defaultdict\n", "from pathlib import Path, PurePosixPath" ] @@ -136,8 +138,6 @@ }, "outputs": [], "source": [ - "import numpy as np\n", - "import pandas as pd\n", "files = pd.DataFrame(columns='FMH\tfile_id\tfile_type\tfile_path\tfile_mapping'.split('\\t'))\n", "files['file_path'] = pd.read_csv(file, header=None)\n", "files['FMH'] = 'FMH'\n", @@ -165,9 +165,7 @@ { "cell_type": "markdown", "id": "9107e219", - "metadata": { - "lines_to_next_cell": 2 - }, + "metadata": {}, "source": [ "Some manuel adding of the last files still required..." ] diff --git a/project/00_0_4_create_submission_folder.py b/project/00_0_4_create_submission_folder.py index 3078981f5..91ad14fdf 100644 --- a/project/00_0_4_create_submission_folder.py +++ b/project/00_0_4_create_submission_folder.py @@ -3,6 +3,8 @@ # %% +import pandas as pd +import numpy as np from collections import defaultdict from pathlib import Path, PurePosixPath @@ -62,8 +64,6 @@ '.tsv': 'EXPERIMENTAL_DESIGN'} # %% -import numpy as np -import pandas as pd files = pd.DataFrame(columns='FMH file_id file_type file_path file_mapping'.split('\t')) files['file_path'] = pd.read_csv(file, header=None) files['FMH'] = 'FMH' @@ -78,4 +78,3 @@ files.to_csv(FOLDER / 'submiss.px_to_add.tsv', sep='\t', index=False) # %% [markdown] # Some manuel adding of the last files still required... - diff --git a/project/00_0_hela_metadata_rawfiles.ipynb b/project/00_0_hela_metadata_rawfiles.ipynb index 820e3bfec..3971259e4 100644 --- a/project/00_0_hela_metadata_rawfiles.ipynb +++ b/project/00_0_hela_metadata_rawfiles.ipynb @@ -49,9 +49,11 @@ "source": [ "fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' # Machine parsed metadata from rawfile workflow\n", "# outputs\n", - "fn_files_per_instrument: str = 'data/files_per_instrument.yaml' # All parsed raw files nested by instrument (model, attribute, serial number)\n", + "# All parsed raw files nested by instrument (model, attribute, serial number)\n", + "fn_files_per_instrument: str = 'data/files_per_instrument.yaml'\n", "fn_files_selected: str = 'data/samples_selected.yaml' # selected files based on threshold of identified peptides\n", - "fn_files_per_instrument_selected: str = 'data/files_selected_per_instrument.yaml' # Selected parsed raw files nested by instrument (model, attribute, serial number)" + "# Selected parsed raw files nested by instrument (model, attribute, serial number)\n", + "fn_files_per_instrument_selected: str = 'data/files_selected_per_instrument.yaml'" ] }, { diff --git a/project/00_0_hela_metadata_rawfiles.py b/project/00_0_hela_metadata_rawfiles.py index b8f1248df..03a501db0 100644 --- a/project/00_0_hela_metadata_rawfiles.py +++ b/project/00_0_hela_metadata_rawfiles.py @@ -34,9 +34,11 @@ # %% tags=["parameters"] fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' # Machine parsed metadata from rawfile workflow # outputs -fn_files_per_instrument: str = 'data/files_per_instrument.yaml' # All parsed raw files nested by instrument (model, attribute, serial number) +# All parsed raw files nested by instrument (model, attribute, serial number) +fn_files_per_instrument: str = 'data/files_per_instrument.yaml' fn_files_selected: str = 'data/samples_selected.yaml' # selected files based on threshold of identified peptides -fn_files_per_instrument_selected: str = 'data/files_selected_per_instrument.yaml' # Selected parsed raw files nested by instrument (model, attribute, serial number) +# Selected parsed raw files nested by instrument (model, attribute, serial number) +fn_files_per_instrument_selected: str = 'data/files_selected_per_instrument.yaml' # %% [markdown] # ### Machine metadata diff --git a/project/00_1_hela_MQ_summaries.ipynb b/project/00_1_hela_MQ_summaries.ipynb index 9cd1dee49..4b563a2ad 100644 --- a/project/00_1_hela_MQ_summaries.ipynb +++ b/project/00_1_hela_MQ_summaries.ipynb @@ -22,7 +22,10 @@ "import yaml\n", "import numpy as np\n", "import pandas as pd\n", + "\n", "import vaep\n", + "from vaep.pandas import get_unique_non_unique_columns\n", + "from vaep.pandas import unique_cols\n", "\n", "from config import FN_ALL_SUMMARIES\n", "print(f\"{FN_ALL_SUMMARIES = }\")" @@ -39,7 +42,7 @@ }, "outputs": [], "source": [ - "FN_ALL_SUMMARIES: str = 'data/mq_summaries.csv' # MqAllSummaries json" + "FN_ALL_SUMMARIES: str = 'data/mq_summaries.csv' # MqAllSummaries json" ] }, { @@ -65,7 +68,6 @@ "metadata": {}, "outputs": [], "source": [ - "from vaep.pandas import unique_cols\n", "unique_cols(mq_all_summaries.Multiplicity), unique_cols(\n", " mq_all_summaries[\"Variable modifications first search\"]) # int, NA" ] @@ -76,7 +78,6 @@ "metadata": {}, "outputs": [], "source": [ - "from vaep.pandas import get_unique_non_unique_columns\n", "columns = get_unique_non_unique_columns(mq_all_summaries)\n", "mq_all_summaries[columns.unique]" ] @@ -114,19 +115,23 @@ "source": [ "class col_summary:\n", " MS1 = 'MS'\n", - " MS2 = 'MS/MS' \n", - " MS2_identified = 'MS/MS Identified'\n", + " MS2 = 'MS/MS'\n", + " MS2_identified = 'MS/MS Identified'\n", " peptides_identified = 'Peptide Sequences Identified'\n", "\n", + "\n", "if mq_all_summaries is None:\n", " raise ValueError(\"No data assigned\")\n", - " \n", - "MS_spectra = mq_all_summaries[[col_summary.MS1, col_summary.MS2, col_summary.MS2_identified, col_summary.peptides_identified]]\n", + "\n", + "MS_spectra = mq_all_summaries[[col_summary.MS1, col_summary.MS2,\n", + " col_summary.MS2_identified, col_summary.peptides_identified]]\n", + "\n", "\n", "def compute_summary(threshold_identified):\n", - " mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified\n", + " mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified\n", " display(MS_spectra.loc[mask].describe(np.linspace(0.05, 0.95, 10)))\n", "\n", + "\n", "w_ions_range = widgets.IntSlider(value=15_000, min=15_000, max=MS_spectra[col_summary.peptides_identified].max())\n", "display(widgets.interactive(compute_summary, threshold_identified=w_ions_range))" ] @@ -160,9 +165,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "lines_to_next_cell": 2 - }, + "metadata": {}, "outputs": [], "source": [ "dump_dict = {'threshold': int(w_ions_range.value)}\n", diff --git a/project/00_1_hela_MQ_summaries.py b/project/00_1_hela_MQ_summaries.py index 496b0da07..2a27a89d4 100644 --- a/project/00_1_hela_MQ_summaries.py +++ b/project/00_1_hela_MQ_summaries.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: vaep # language: python @@ -25,13 +25,16 @@ import yaml import numpy as np import pandas as pd + import vaep +from vaep.pandas import get_unique_non_unique_columns +from vaep.pandas import unique_cols from config import FN_ALL_SUMMARIES print(f"{FN_ALL_SUMMARIES = }") # %% tags=["parameters"] -FN_ALL_SUMMARIES: str = 'data/mq_summaries.csv' # MqAllSummaries json +FN_ALL_SUMMARIES: str = 'data/mq_summaries.csv' # MqAllSummaries json # %% @@ -42,12 +45,10 @@ # Find unique columns, see [post](https://stackoverflow.com/a/54405767/9684872) # %% -from vaep.pandas import unique_cols unique_cols(mq_all_summaries.Multiplicity), unique_cols( mq_all_summaries["Variable modifications first search"]) # int, NA # %% -from vaep.pandas import get_unique_non_unique_columns columns = get_unique_non_unique_columns(mq_all_summaries) mq_all_summaries[columns.unique] @@ -64,19 +65,23 @@ # %% class col_summary: MS1 = 'MS' - MS2 = 'MS/MS' - MS2_identified = 'MS/MS Identified' + MS2 = 'MS/MS' + MS2_identified = 'MS/MS Identified' peptides_identified = 'Peptide Sequences Identified' + if mq_all_summaries is None: raise ValueError("No data assigned") - -MS_spectra = mq_all_summaries[[col_summary.MS1, col_summary.MS2, col_summary.MS2_identified, col_summary.peptides_identified]] + +MS_spectra = mq_all_summaries[[col_summary.MS1, col_summary.MS2, + col_summary.MS2_identified, col_summary.peptides_identified]] + def compute_summary(threshold_identified): - mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified + mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified display(MS_spectra.loc[mask].describe(np.linspace(0.05, 0.95, 10))) + w_ions_range = widgets.IntSlider(value=15_000, min=15_000, max=MS_spectra[col_summary.peptides_identified].max()) display(widgets.interactive(compute_summary, threshold_identified=w_ions_range)) @@ -99,4 +104,3 @@ def compute_summary(threshold_identified): with open('data/samples_selected.yaml', 'w') as f: yaml.dump(dump_dict, stream=f) - diff --git a/project/00_2_hela_all_raw_files.ipynb b/project/00_2_hela_all_raw_files.ipynb index 40ff06b32..384a5aa09 100644 --- a/project/00_2_hela_all_raw_files.ipynb +++ b/project/00_2_hela_all_raw_files.ipynb @@ -35,7 +35,7 @@ "find . -name '*.raw' -ls > all_raw_files_dump_2021_10_27.txt\n", "```\n", "\n", - "which was executed in the " + "which was executed in the" ] }, { @@ -82,7 +82,7 @@ "# FN_ALL_RAW_FILES = config.FOLDER_DATA / config.FN_ALL_RAW_FILES\n", "FN_ALL_RAW_FILES: str = config.FOLDER_DATA / 'all_raw_files_dump_2021_10_29.txt'\n", "FN_ALL_SUMMARIES: str = config.FN_ALL_SUMMARIES\n", - "FN_PEPTIDE_INTENSITIES = config.FOLDER_DATA / 'df_intensities_N07285_M01000' " + "FN_PEPTIDE_INTENSITIES = config.FOLDER_DATA / 'df_intensities_N07285_M01000'" ] }, { @@ -107,7 +107,7 @@ "data = []\n", "with open(cfg.FN_ALL_RAW_FILES) as f:\n", " for line in f:\n", - " line = line.split(maxsplit=8) # ignore white spaces in file names, example:\n", + " line = line.split(maxsplit=8) # ignore white spaces in file names, example:\n", " #'-rw-r--r--. 1 501 501 282917566 Dec 3 2022 ./share_hela_raw/MNT_202220220921_EXLP1_Evo1_LiNi_ - Copy1.raw'\n", " path = Path(line[-1].strip())\n", " data.append(RawFile(path.stem, path, int(line[4])))\n", @@ -158,7 +158,7 @@ "mask_non_unique = data.reset_index().duplicated(subset=['name', 'bytes'])\n", "mask_non_unique.index = data.index\n", "idx_non_unique = data.loc[mask_non_unique].index.unique()\n", - "idx_non_unique # min number of files to remove" + "idx_non_unique # min number of files to remove" ] }, { @@ -178,6 +178,7 @@ " print(f'Number of files with more than 2 duplicates: {(non_unique > 2).sum()}')\n", " return non_unique\n", "\n", + "\n", "non_unique = check_for_duplicates(df=data)\n", "non_unique" ] @@ -196,7 +197,7 @@ "outputs": [], "source": [ "data.loc[\n", - " non_unique.index.difference(idx_non_unique) ]" + " non_unique.index.difference(idx_non_unique)]" ] }, { @@ -220,14 +221,15 @@ " non_unique_remaining = pd.DataFrame()\n", " for idx, g in _data_to_remove.groupby(level=0):\n", " mask = ['\\\\MNT' in str(x) for x in g.path]\n", - " assert len(mask) != sum(mask) , f'All files in MNT subfolders: {idx}'\n", + " assert len(mask) != sum(mask), f'All files in MNT subfolders: {idx}'\n", " data_in_MNT_to_remove = data_in_MNT_to_remove.append(g[mask])\n", - " non_unique_remaining = non_unique_remaining.append(g[[x!=True for x in mask]])\n", + " non_unique_remaining = non_unique_remaining.append(g[[x != True for x in mask]])\n", "\n", " del _data_to_remove, mask, idx, g\n", "\n", "assert len(data.loc[idx_non_unique]) == len(non_unique_remaining) + len(data_in_MNT_to_remove)\n", - "assert len(non_unique_remaining.loc[['\\\\MNT' in str(x) for x in non_unique_remaining.path]]) == 0, \"There are files in MNT folder left\"\n", + "assert len(non_unique_remaining.loc[['\\\\MNT' in str(x)\n", + " for x in non_unique_remaining.path]]) == 0, \"There are files in MNT folder left\"\n", "data_in_MNT_to_remove" ] }, @@ -264,7 +266,7 @@ "mask_non_unique_remaining = non_unique_remaining.reset_index().duplicated(subset=['name', 'bytes'])\n", "mask_non_unique_remaining.index = non_unique_remaining.index\n", "data_to_remove = data_in_MNT_to_remove.append(\n", - " non_unique_remaining.loc[mask_non_unique_remaining]\n", + " non_unique_remaining.loc[mask_non_unique_remaining]\n", ")\n", "data_to_remove" ] @@ -284,7 +286,8 @@ "metadata": {}, "outputs": [], "source": [ - "data_unique = data.reset_index().set_index('num_index').drop(data_to_remove.set_index('num_index').index).set_index('name')\n", + "data_unique = data.reset_index().set_index('num_index').drop(\n", + " data_to_remove.set_index('num_index').index).set_index('name')\n", "data_unique" ] }, @@ -310,7 +313,7 @@ "metadata": {}, "outputs": [], "source": [ - "assert len(data_unique) + len(data_to_remove) == len(data)" + "assert len(data_unique) + len(data_to_remove) == len(data)" ] }, { @@ -343,7 +346,9 @@ "metadata": {}, "outputs": [], "source": [ - "cfg.FN_ALL_RAW_FILES_UNIQUE = utils.append_to_filepath(cfg.FN_ALL_RAW_FILES, config.build_df_fname(data_unique, 'unique'), new_suffix='csv')\n", + "cfg.FN_ALL_RAW_FILES_UNIQUE = utils.append_to_filepath(\n", + " cfg.FN_ALL_RAW_FILES, config.build_df_fname(\n", + " data_unique, 'unique'), new_suffix='csv')\n", "data_unique.to_csv(cfg.FN_ALL_RAW_FILES_UNIQUE)" ] }, @@ -474,13 +479,13 @@ " # continue with samples below 2019 (select in DropDown below)\n", " '20180508_QE3_nLC5_DBJ_DIAprot_HELA_500ng_GPF',\n", " '20180528_QE5_Evo2_DBJ_DIAprot_HeLa_500ng',\n", - " '20190108_QE7_Evo1_DBJ_SA_LFQpho_HELA_PACs_200ug', # s mssing in LFQphos\n", + " '20190108_QE7_Evo1_DBJ_SA_LFQpho_HELA_PACs_200ug', # s mssing in LFQphos\n", " '20190108_QE7_Evo1_DBJ_SA_LFQphos_HELA_PAC_200ug',\n", " '20190108_QE7_Evo1_DBJ_SA_LFQphos_HELA_PAC_300ug',\n", " '20190108_QE7_Evo1_DBJ_SA_LFQphos_HELA_PAC_400ug',\n", " '20190212_QE5_Evo1_DBJ_LFQprot',\n", " '20190314_QE3_DBJ_Evo2_LFQphos_Hela_200ug_StageTip',\n", - " '20190314_QE3_DBJ_Evo2_LFQphos_Hela_380ug_StageTip', # first t missing in StagetTip\n", + " '20190314_QE3_DBJ_Evo2_LFQphos_Hela_380ug_StageTip', # first t missing in StagetTip\n", " '20190314_QE3_DBJ_Evo2_LFQphos_Hela_380ug_StagetTip',\n", " '20190402_QE3_Evo1_DBJ_DIAprot_HELA',\n", " '20190402_QE3_Evo1_DBJ_LFQprot_HELA',\n", @@ -489,7 +494,7 @@ " '20190507_QE5_Evo1_DBJ_LFQprot_Subcell_HeLa_Ctrl',\n", " '20190507_QE5_Evo1_DBJ_LFQprot_Subcell_library_HeLa_Ctrl_Ani_Mix',\n", " '20190622_EXP1_Evo1_AMV_SubCell-library-HeLa_21min-30000',\n", - " '20190628_EXP1_Evo1_AMV_SubCell-library-HeLa_21min-30000', \n", + " '20190628_EXP1_Evo1_AMV_SubCell-library-HeLa_21min-30000',\n", "]\n", "\n", "# exclude keys and handle separately. Remaining keys can be used directly to create list of inputs.\n", @@ -505,7 +510,7 @@ "w_data = widgets.Dropdown(options=frac_unique, index=0)\n", "show_fractions_frac = partial(show_fractions, df=df_selected)\n", "out_sel = widgets.interactive_output(show_fractions_frac, {'stub': w_data})\n", - "widgets.VBox([w_data, out_sel]) # repr of class\n", + "widgets.VBox([w_data, out_sel]) # repr of class\n", "#stub, export" ] }, @@ -715,7 +720,7 @@ "metadata": {}, "outputs": [], "source": [ - "analysis = AnalyzePeptides.from_csv(cfg.FN_ALL_RAW_FILES_UNIQUE,index_col='name') # ToDo: Add numbers to file names\n", + "analysis = AnalyzePeptides.from_csv(cfg.FN_ALL_RAW_FILES_UNIQUE, index_col='name') # ToDo: Add numbers to file names\n", "analysis.df" ] }, @@ -745,7 +750,7 @@ "metadata": {}, "outputs": [], "source": [ - "analysis.df.loc[analysis.df.index.duplicated(False)] # keep the larger one" + "analysis.df.loc[analysis.df.index.duplicated(False)] # keep the larger one" ] }, { @@ -761,7 +766,7 @@ "metadata": {}, "outputs": [], "source": [ - "vars(cfg) # return a dict which is rendered differently in ipython" + "vars(cfg) # return a dict which is rendered differently in ipython" ] }, { diff --git a/project/00_2_hela_all_raw_files.py b/project/00_2_hela_all_raw_files.py index bde0f37db..06949d392 100644 --- a/project/00_2_hela_all_raw_files.py +++ b/project/00_2_hela_all_raw_files.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -44,7 +44,7 @@ # find . -name '*.raw' -ls > all_raw_files_dump_2021_10_27.txt # ``` # -# which was executed in the +# which was executed in the # %% from pathlib import Path, PurePosixPath @@ -75,7 +75,7 @@ # FN_ALL_RAW_FILES = config.FOLDER_DATA / config.FN_ALL_RAW_FILES FN_ALL_RAW_FILES: str = config.FOLDER_DATA / 'all_raw_files_dump_2021_10_29.txt' FN_ALL_SUMMARIES: str = config.FN_ALL_SUMMARIES -FN_PEPTIDE_INTENSITIES = config.FOLDER_DATA / 'df_intensities_N07285_M01000' +FN_PEPTIDE_INTENSITIES = config.FOLDER_DATA / 'df_intensities_N07285_M01000' # %% cfg.FN_ALL_RAW_FILES = FN_ALL_RAW_FILES @@ -88,7 +88,7 @@ data = [] with open(cfg.FN_ALL_RAW_FILES) as f: for line in f: - line = line.split(maxsplit=8) # ignore white spaces in file names, example: + line = line.split(maxsplit=8) # ignore white spaces in file names, example: #'-rw-r--r--. 1 501 501 282917566 Dec 3 2022 ./share_hela_raw/MNT_202220220921_EXLP1_Evo1_LiNi_ - Copy1.raw' path = Path(line[-1].strip()) data.append(RawFile(path.stem, path, int(line[4]))) @@ -117,7 +117,7 @@ mask_non_unique = data.reset_index().duplicated(subset=['name', 'bytes']) mask_non_unique.index = data.index idx_non_unique = data.loc[mask_non_unique].index.unique() -idx_non_unique # min number of files to remove +idx_non_unique # min number of files to remove # %% @@ -132,6 +132,7 @@ def check_for_duplicates(df): print(f'Number of files with more than 2 duplicates: {(non_unique > 2).sum()}') return non_unique + non_unique = check_for_duplicates(df=data) non_unique @@ -140,7 +141,7 @@ def check_for_duplicates(df): # %% data.loc[ - non_unique.index.difference(idx_non_unique) ] + non_unique.index.difference(idx_non_unique)] # %% [markdown] # For same sized groups, remove first the onces in the `MNT` folder: @@ -154,14 +155,15 @@ def check_for_duplicates(df): non_unique_remaining = pd.DataFrame() for idx, g in _data_to_remove.groupby(level=0): mask = ['\\MNT' in str(x) for x in g.path] - assert len(mask) != sum(mask) , f'All files in MNT subfolders: {idx}' + assert len(mask) != sum(mask), f'All files in MNT subfolders: {idx}' data_in_MNT_to_remove = data_in_MNT_to_remove.append(g[mask]) - non_unique_remaining = non_unique_remaining.append(g[[x!=True for x in mask]]) + non_unique_remaining = non_unique_remaining.append(g[[x != True for x in mask]]) del _data_to_remove, mask, idx, g assert len(data.loc[idx_non_unique]) == len(non_unique_remaining) + len(data_in_MNT_to_remove) -assert len(non_unique_remaining.loc[['\\MNT' in str(x) for x in non_unique_remaining.path]]) == 0, "There are files in MNT folder left" +assert len(non_unique_remaining.loc[['\\MNT' in str(x) + for x in non_unique_remaining.path]]) == 0, "There are files in MNT folder left" data_in_MNT_to_remove # %% [markdown] @@ -178,7 +180,7 @@ def check_for_duplicates(df): mask_non_unique_remaining = non_unique_remaining.reset_index().duplicated(subset=['name', 'bytes']) mask_non_unique_remaining.index = non_unique_remaining.index data_to_remove = data_in_MNT_to_remove.append( - non_unique_remaining.loc[mask_non_unique_remaining] + non_unique_remaining.loc[mask_non_unique_remaining] ) data_to_remove @@ -186,7 +188,8 @@ def check_for_duplicates(df): print(f"Save {data_to_remove['size_gb'].sum():1.0f} GB disk space by deleting {len(data_to_remove)} files.") # %% -data_unique = data.reset_index().set_index('num_index').drop(data_to_remove.set_index('num_index').index).set_index('name') +data_unique = data.reset_index().set_index('num_index').drop( + data_to_remove.set_index('num_index').index).set_index('name') data_unique # %% [markdown] @@ -196,7 +199,7 @@ def check_for_duplicates(df): data_unique.loc[data_to_remove.index.unique()] # %% -assert len(data_unique) + len(data_to_remove) == len(data) +assert len(data_unique) + len(data_to_remove) == len(data) # %% [markdown] # Show files which are duplicated, but have different sizes: @@ -209,7 +212,9 @@ def check_for_duplicates(df): # Save unique files # %% -cfg.FN_ALL_RAW_FILES_UNIQUE = utils.append_to_filepath(cfg.FN_ALL_RAW_FILES, config.build_df_fname(data_unique, 'unique'), new_suffix='csv') +cfg.FN_ALL_RAW_FILES_UNIQUE = utils.append_to_filepath( + cfg.FN_ALL_RAW_FILES, config.build_df_fname( + data_unique, 'unique'), new_suffix='csv') data_unique.to_csv(cfg.FN_ALL_RAW_FILES_UNIQUE) # %% [markdown] @@ -280,13 +285,13 @@ def check_for_duplicates(df): # continue with samples below 2019 (select in DropDown below) '20180508_QE3_nLC5_DBJ_DIAprot_HELA_500ng_GPF', '20180528_QE5_Evo2_DBJ_DIAprot_HeLa_500ng', - '20190108_QE7_Evo1_DBJ_SA_LFQpho_HELA_PACs_200ug', # s mssing in LFQphos + '20190108_QE7_Evo1_DBJ_SA_LFQpho_HELA_PACs_200ug', # s mssing in LFQphos '20190108_QE7_Evo1_DBJ_SA_LFQphos_HELA_PAC_200ug', '20190108_QE7_Evo1_DBJ_SA_LFQphos_HELA_PAC_300ug', '20190108_QE7_Evo1_DBJ_SA_LFQphos_HELA_PAC_400ug', '20190212_QE5_Evo1_DBJ_LFQprot', '20190314_QE3_DBJ_Evo2_LFQphos_Hela_200ug_StageTip', - '20190314_QE3_DBJ_Evo2_LFQphos_Hela_380ug_StageTip', # first t missing in StagetTip + '20190314_QE3_DBJ_Evo2_LFQphos_Hela_380ug_StageTip', # first t missing in StagetTip '20190314_QE3_DBJ_Evo2_LFQphos_Hela_380ug_StagetTip', '20190402_QE3_Evo1_DBJ_DIAprot_HELA', '20190402_QE3_Evo1_DBJ_LFQprot_HELA', @@ -295,7 +300,7 @@ def check_for_duplicates(df): '20190507_QE5_Evo1_DBJ_LFQprot_Subcell_HeLa_Ctrl', '20190507_QE5_Evo1_DBJ_LFQprot_Subcell_library_HeLa_Ctrl_Ani_Mix', '20190622_EXP1_Evo1_AMV_SubCell-library-HeLa_21min-30000', - '20190628_EXP1_Evo1_AMV_SubCell-library-HeLa_21min-30000', + '20190628_EXP1_Evo1_AMV_SubCell-library-HeLa_21min-30000', ] # exclude keys and handle separately. Remaining keys can be used directly to create list of inputs. @@ -305,7 +310,7 @@ def check_for_duplicates(df): w_data = widgets.Dropdown(options=frac_unique, index=0) show_fractions_frac = partial(show_fractions, df=df_selected) out_sel = widgets.interactive_output(show_fractions_frac, {'stub': w_data}) -widgets.VBox([w_data, out_sel]) # repr of class +widgets.VBox([w_data, out_sel]) # repr of class #stub, export # %% [markdown] @@ -406,7 +411,7 @@ def check_for_duplicates(df): # ### From file name # %% -analysis = AnalyzePeptides.from_csv(cfg.FN_ALL_RAW_FILES_UNIQUE,index_col='name') # ToDo: Add numbers to file names +analysis = AnalyzePeptides.from_csv(cfg.FN_ALL_RAW_FILES_UNIQUE, index_col='name') # ToDo: Add numbers to file names analysis.df # %% @@ -416,12 +421,12 @@ def check_for_duplicates(df): # Metadata has fewer cases due to duplicates with differnt file sizes ( see above) # %% -analysis.df.loc[analysis.df.index.duplicated(False)] # keep the larger one +analysis.df.loc[analysis.df.index.duplicated(False)] # keep the larger one # %% [markdown] # ## cfg # %% -vars(cfg) # return a dict which is rendered differently in ipython +vars(cfg) # return a dict which is rendered differently in ipython # %% diff --git a/project/00_3_0_pride_metadata_creation.ipynb b/project/00_3_0_pride_metadata_creation.ipynb index 624189c69..a074c91f5 100644 --- a/project/00_3_0_pride_metadata_creation.ipynb +++ b/project/00_3_0_pride_metadata_creation.ipynb @@ -7,7 +7,7 @@ "source": [ "# Selected files\n", "\n", - "- document metadata and file sizes of published dataset in Scientific Data Report \n", + "- document metadata and file sizes of published dataset in Scientific Data Report\n", "\n", "## Contents\n", "\n", @@ -45,11 +45,11 @@ "metadata": {}, "outputs": [], "source": [ - "fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id\n", - "fn_raw_file_size: str = 'processed/all_raw_file_sizes.csv' # raw file sizes\n", + "fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id\n", + "fn_raw_file_size: str = 'processed/all_raw_file_sizes.csv' # raw file sizes\n", "fn_rawfile_metadata: str = 'data/rawfile_metadata.csv'\n", - "fn_summaries:str = 'data/processed/all_summaries.json'\n", - "date_col:str = 'Content Creation Date'\n", + "fn_summaries: str = 'data/processed/all_summaries.json'\n", + "date_col: str = 'Content Creation Date'\n", "out_folder: str = 'data/dev_datasets/pride_upload'" ] }, @@ -140,7 +140,6 @@ "metadata": {}, "outputs": [], "source": [ - "from pathlib import Path\n", "df_raw_file_size['path'] = df_raw_file_size['path'].apply(lambda x: Path(x).as_posix())\n", "df_raw_file_size = df_raw_file_size.reset_index().set_index('path')\n", "df_raw_file_size" @@ -195,7 +194,7 @@ "outputs": [], "source": [ "df_meta = df_meta.loc[df_ids.index]\n", - "df_meta.columns = df_meta.columns.droplevel() # remove top level name\n", + "df_meta.columns = df_meta.columns.droplevel() # remove top level name\n", "df_meta" ] }, @@ -239,7 +238,7 @@ " .join(df_raw_file_size)\n", " .join(df_meta)\n", " .join(df_summaries)\n", - " )\n", + " )\n", "df_meta" ] }, @@ -263,11 +262,11 @@ "source": [ "df_meta = (df_meta\n", " .drop(['Path_old', 'Pathname', 'path'], axis=1)\n", - " .rename({'Path_new':'Pathname'}, axis=1)\n", + " .rename({'Path_new': 'Pathname'}, axis=1)\n", " .dropna(how='all', axis=1)\n", " .convert_dtypes()\n", " .assign(**{date_col: lambda df_meta: pd.to_datetime(df_meta[date_col])})\n", - ")\n", + " )\n", "df_meta" ] }, @@ -323,12 +322,12 @@ "dtypes = pd.read_json(\n", " files_out['pride_metadata_schema.json'],\n", " orient='index'\n", - " ).squeeze()\n", - "mask_dates = dtypes.str.contains('datetime') # date columns need to be provide separately\n", + ").squeeze()\n", + "mask_dates = dtypes.str.contains('datetime') # date columns need to be provide separately\n", "pd.read_csv(files_out['pride_metadata.csv'],\n", " parse_dates=mask_dates.loc[mask_dates].index.to_list(),\n", " dtype=dtypes.loc[~mask_dates].to_dict()\n", - ").dtypes" + " ).dtypes" ] }, { diff --git a/project/00_3_0_pride_metadata_creation.py b/project/00_3_0_pride_metadata_creation.py index 17594453d..9165f16b2 100644 --- a/project/00_3_0_pride_metadata_creation.py +++ b/project/00_3_0_pride_metadata_creation.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -15,7 +15,7 @@ # %% [markdown] # # Selected files # -# - document metadata and file sizes of published dataset in Scientific Data Report +# - document metadata and file sizes of published dataset in Scientific Data Report # # ## Contents # @@ -33,11 +33,11 @@ # ## PARAMETERS # %% -fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id -fn_raw_file_size: str = 'processed/all_raw_file_sizes.csv' # raw file sizes +fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id +fn_raw_file_size: str = 'processed/all_raw_file_sizes.csv' # raw file sizes fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' -fn_summaries:str = 'data/processed/all_summaries.json' -date_col:str = 'Content Creation Date' +fn_summaries: str = 'data/processed/all_summaries.json' +date_col: str = 'Content Creation Date' out_folder: str = 'data/dev_datasets/pride_upload' # %% [markdown] @@ -71,7 +71,6 @@ df_raw_file_size.index.is_unique # %% -from pathlib import Path df_raw_file_size['path'] = df_raw_file_size['path'].apply(lambda x: Path(x).as_posix()) df_raw_file_size = df_raw_file_size.reset_index().set_index('path') df_raw_file_size @@ -93,7 +92,7 @@ # %% df_meta = df_meta.loc[df_ids.index] -df_meta.columns = df_meta.columns.droplevel() # remove top level name +df_meta.columns = df_meta.columns.droplevel() # remove top level name df_meta # %% [markdown] @@ -113,7 +112,7 @@ .join(df_raw_file_size) .join(df_meta) .join(df_summaries) - ) + ) df_meta # %% @@ -123,11 +122,11 @@ # %% df_meta = (df_meta .drop(['Path_old', 'Pathname', 'path'], axis=1) - .rename({'Path_new':'Pathname'}, axis=1) + .rename({'Path_new': 'Pathname'}, axis=1) .dropna(how='all', axis=1) .convert_dtypes() .assign(**{date_col: lambda df_meta: pd.to_datetime(df_meta[date_col])}) -) + ) df_meta # %% [markdown] @@ -152,12 +151,12 @@ dtypes = pd.read_json( files_out['pride_metadata_schema.json'], orient='index' - ).squeeze() -mask_dates = dtypes.str.contains('datetime') # date columns need to be provide separately +).squeeze() +mask_dates = dtypes.str.contains('datetime') # date columns need to be provide separately pd.read_csv(files_out['pride_metadata.csv'], parse_dates=mask_dates.loc[mask_dates].index.to_list(), dtype=dtypes.loc[~mask_dates].to_dict() -).dtypes + ).dtypes # %% diff --git a/project/00_3_1_pride_metadata_analysis.ipynb b/project/00_3_1_pride_metadata_analysis.ipynb index 75f62cdf8..d68e970a9 100644 --- a/project/00_3_1_pride_metadata_analysis.ipynb +++ b/project/00_3_1_pride_metadata_analysis.ipynb @@ -110,41 +110,41 @@ "# Orbitrap Fusion Lumos MS:1002732\n", "\n", "instrument_labels = {'Q-Exactive-Orbitrap_1': 'Q Exactive 1',\n", - " 'Q-Exactive-Plus-Orbitrap_1': 'Exactive Plus 1',\n", - " 'Q-Exactive-HF-Orbitrap_206': 'Q Exactive HF 206',\n", - " 'Q-Exactive-Plus-Orbitrap_143': 'Exactive Plus 143',\n", - " 'Q-Exactive-HF-Orbitrap_1': 'Q Exactive HF 1',\n", - " 'Q-Exactive-HF-Orbitrap_147': 'Q Exactive HF 147',\n", - " 'Q-Exactive-HF-Orbitrap_204': 'Q Exactive HF 204',\n", - " 'Q-Exactive-HF-Orbitrap_148': 'Q Exactive HF 148',\n", - " 'Q-Exactive-HF-Orbitrap_207': 'Q Exactive HF 207',\n", - " 'Q-Exactive-HF-Orbitrap_143': 'Q Exactive HF 143',\n", - " 'Orbitrap-Fusion-Lumos_FSN20115': 'Orbitrap Fusion Lumos FSN20115',\n", - " 'Q-Exactive-HF-Orbitrap_2612': 'Q Exactive HF 2612',\n", - " 'Q-Exactive-HF-X-Orbitrap_6016': 'Q Exactive HF-X 6016',\n", - " 'Q-Exactive-HF-X-Orbitrap_6004': 'Q Exactive HF-X 6004',\n", - " 'Q-Exactive-HF-X-Orbitrap_6075': 'Q Exactive HF-X 6075',\n", - " 'Q-Exactive-HF-X-Orbitrap_6078': 'Q Exactive HF-X 6078',\n", - " 'Q-Exactive-HF-X-Orbitrap_6070': 'Q Exactive HF-X 6070',\n", - " 'Q-Exactive-HF-X-Orbitrap_6071': 'Q Exactive HF-X 6071',\n", - " 'Q-Exactive-HF-X-Orbitrap_6011': 'Q Exactive HF-X 6011',\n", - " 'Q-Exactive-HF-X-Orbitrap_6073': 'Q Exactive HF-X 6073',\n", - " 'Q-Exactive-HF-X-Orbitrap_6101': 'Q Exactive HF-X 6101',\n", - " 'Q-Exactive-HF-X-Orbitrap_6096': 'Q Exactive HF-X 6096',\n", - " 'Exactive-Series-Orbitrap_6004': 'Exactive Series 6004',\n", - " 'Q-Exactive-HF-X-Orbitrap_6043': 'Q Exactive HF-X 6043',\n", - " 'Q-Exactive-HF-X-Orbitrap_6025': 'Q Exactive HF-X 6025',\n", - " 'Q-Exactive-HF-X-Orbitrap_6022': 'Q Exactive HF-X 6022',\n", - " 'Q-Exactive-HF-X-Orbitrap_6023': 'Q Exactive HF-X 6023',\n", - " 'Q-Exactive-HF-X-Orbitrap_6028': 'Q Exactive HF-X 6028',\n", - " 'Q-Exactive-HF-X-Orbitrap_6013': 'Q Exactive HF-X 6013',\n", - " 'Q-Exactive-HF-X-Orbitrap_6044': 'Q Exactive HF-X 6044',\n", - " 'Q-Exactive-HF-X-Orbitrap_6324': 'Q Exactive HF-X 6324',\n", - " 'Orbitrap-Exploris-480_Invalid_SN_0001': 'Orbitrap Exploris 480 Invalid SN 0001',\n", - " 'Orbitrap-Exploris-480_MA10134C': 'Orbitrap Exploris 480 MA10134C',\n", - " 'Orbitrap-Exploris-480_MA10132C': 'Orbitrap Exploris 480 MA10132C',\n", - " 'Orbitrap-Exploris-480_MA10130C': 'Orbitrap Exploris 480 MA10130C',\n", - " 'Orbitrap-Exploris-480_MA10215C': 'Orbitrap Exploris 480 MA10215C'}\n", + " 'Q-Exactive-Plus-Orbitrap_1': 'Exactive Plus 1',\n", + " 'Q-Exactive-HF-Orbitrap_206': 'Q Exactive HF 206',\n", + " 'Q-Exactive-Plus-Orbitrap_143': 'Exactive Plus 143',\n", + " 'Q-Exactive-HF-Orbitrap_1': 'Q Exactive HF 1',\n", + " 'Q-Exactive-HF-Orbitrap_147': 'Q Exactive HF 147',\n", + " 'Q-Exactive-HF-Orbitrap_204': 'Q Exactive HF 204',\n", + " 'Q-Exactive-HF-Orbitrap_148': 'Q Exactive HF 148',\n", + " 'Q-Exactive-HF-Orbitrap_207': 'Q Exactive HF 207',\n", + " 'Q-Exactive-HF-Orbitrap_143': 'Q Exactive HF 143',\n", + " 'Orbitrap-Fusion-Lumos_FSN20115': 'Orbitrap Fusion Lumos FSN20115',\n", + " 'Q-Exactive-HF-Orbitrap_2612': 'Q Exactive HF 2612',\n", + " 'Q-Exactive-HF-X-Orbitrap_6016': 'Q Exactive HF-X 6016',\n", + " 'Q-Exactive-HF-X-Orbitrap_6004': 'Q Exactive HF-X 6004',\n", + " 'Q-Exactive-HF-X-Orbitrap_6075': 'Q Exactive HF-X 6075',\n", + " 'Q-Exactive-HF-X-Orbitrap_6078': 'Q Exactive HF-X 6078',\n", + " 'Q-Exactive-HF-X-Orbitrap_6070': 'Q Exactive HF-X 6070',\n", + " 'Q-Exactive-HF-X-Orbitrap_6071': 'Q Exactive HF-X 6071',\n", + " 'Q-Exactive-HF-X-Orbitrap_6011': 'Q Exactive HF-X 6011',\n", + " 'Q-Exactive-HF-X-Orbitrap_6073': 'Q Exactive HF-X 6073',\n", + " 'Q-Exactive-HF-X-Orbitrap_6101': 'Q Exactive HF-X 6101',\n", + " 'Q-Exactive-HF-X-Orbitrap_6096': 'Q Exactive HF-X 6096',\n", + " 'Exactive-Series-Orbitrap_6004': 'Exactive Series 6004',\n", + " 'Q-Exactive-HF-X-Orbitrap_6043': 'Q Exactive HF-X 6043',\n", + " 'Q-Exactive-HF-X-Orbitrap_6025': 'Q Exactive HF-X 6025',\n", + " 'Q-Exactive-HF-X-Orbitrap_6022': 'Q Exactive HF-X 6022',\n", + " 'Q-Exactive-HF-X-Orbitrap_6023': 'Q Exactive HF-X 6023',\n", + " 'Q-Exactive-HF-X-Orbitrap_6028': 'Q Exactive HF-X 6028',\n", + " 'Q-Exactive-HF-X-Orbitrap_6013': 'Q Exactive HF-X 6013',\n", + " 'Q-Exactive-HF-X-Orbitrap_6044': 'Q Exactive HF-X 6044',\n", + " 'Q-Exactive-HF-X-Orbitrap_6324': 'Q Exactive HF-X 6324',\n", + " 'Orbitrap-Exploris-480_Invalid_SN_0001': 'Orbitrap Exploris 480 Invalid SN 0001',\n", + " 'Orbitrap-Exploris-480_MA10134C': 'Orbitrap Exploris 480 MA10134C',\n", + " 'Orbitrap-Exploris-480_MA10132C': 'Orbitrap Exploris 480 MA10132C',\n", + " 'Orbitrap-Exploris-480_MA10130C': 'Orbitrap Exploris 480 MA10130C',\n", + " 'Orbitrap-Exploris-480_MA10215C': 'Orbitrap Exploris 480 MA10215C'}\n", "\n", "df_meta[\"instrument_label\"] = df_meta[\"instrument_label\"].replace(instrument_labels)" ] @@ -219,10 +219,10 @@ "\n", "counts_instrument = counts_instrument.join(\n", " (df_meta\n", - " [[*thermo_raw_files.cols_instrument, 'instrument_label']]\n", - " .drop_duplicates()\n", - " .set_index(thermo_raw_files.cols_instrument)\n", - " )\n", + " [[*thermo_raw_files.cols_instrument, 'instrument_label']]\n", + " .drop_duplicates()\n", + " .set_index(thermo_raw_files.cols_instrument)\n", + " )\n", " .set_index('instrument_label', append=True)\n", ")\n", "counts_instrument.to_excel(\n", @@ -286,11 +286,11 @@ "source": [ "fig, ax = plt.subplots()\n", "ax = (counts_instrument\n", - " .plot\n", - " .bar(\n", - " ax=ax,\n", - " )\n", - ")\n", + " .plot\n", + " .bar(\n", + " ax=ax,\n", + " )\n", + " )\n", "ax.set_xlabel('')\n", "ax.set_ylabel('number of samples (runs)')\n", "fname = out_folder / 'number_of_samples_per_instrument.pdf'\n", @@ -331,7 +331,7 @@ "ax = (df_meta\n", " .loc[mask, cols]\n", " .plot\n", - " .scatter(cols[0], cols[1],\n", + " .scatter(cols[0], cols[1],\n", " color='orange',\n", " label='normal files',\n", " ylabel='filesize (in GB)',\n", @@ -362,7 +362,9 @@ "cols = vaep.pandas.get_columns_accessor_from_iterable(cols)\n", "\n", "view = df_meta.loc[mask_top10_instruments]\n", - "view[\"instrument_label+N\"] = view[\"instrument_label\"].replace(counts_instrument.to_frame().apply( lambda s: f\"{s.name} (N={s['count']:03d})\" , axis=1))\n", + "view[\"instrument_label+N\"] = view[\"instrument_label\"].replace(\n", + " counts_instrument.to_frame().apply(\n", + " lambda s: f\"{s.name} (N={s['count']:03d})\", axis=1))\n", "view" ] }, @@ -391,7 +393,7 @@ " title='instrument label',\n", " loc='upper right',\n", " # alignment='left',\n", - ")\n", + " )\n", "ax.xaxis.set_major_formatter(\"{x:,.0f}\")\n", "ax.yaxis.set_major_formatter(\"{x:,.0f}\")\n", "fname = out_folder / 'ms1_to_ms2_top10_instruments.pdf'\n", @@ -457,7 +459,7 @@ "\n", "fig, ax = plt.subplots()\n", "\n", - "ax = ax = seaborn.scatterplot(\n", + "ax = seaborn.scatterplot(\n", " view,\n", " x=cols.MS_max_RT,\n", " y=cols.Peptide_Sequences_Identified,\n", diff --git a/project/00_3_1_pride_metadata_analysis.py b/project/00_3_1_pride_metadata_analysis.py index 2ec9a8fae..c6ad55d12 100644 --- a/project/00_3_1_pride_metadata_analysis.py +++ b/project/00_3_1_pride_metadata_analysis.py @@ -55,41 +55,41 @@ # Orbitrap Fusion Lumos MS:1002732 instrument_labels = {'Q-Exactive-Orbitrap_1': 'Q Exactive 1', - 'Q-Exactive-Plus-Orbitrap_1': 'Exactive Plus 1', - 'Q-Exactive-HF-Orbitrap_206': 'Q Exactive HF 206', - 'Q-Exactive-Plus-Orbitrap_143': 'Exactive Plus 143', - 'Q-Exactive-HF-Orbitrap_1': 'Q Exactive HF 1', - 'Q-Exactive-HF-Orbitrap_147': 'Q Exactive HF 147', - 'Q-Exactive-HF-Orbitrap_204': 'Q Exactive HF 204', - 'Q-Exactive-HF-Orbitrap_148': 'Q Exactive HF 148', - 'Q-Exactive-HF-Orbitrap_207': 'Q Exactive HF 207', - 'Q-Exactive-HF-Orbitrap_143': 'Q Exactive HF 143', - 'Orbitrap-Fusion-Lumos_FSN20115': 'Orbitrap Fusion Lumos FSN20115', - 'Q-Exactive-HF-Orbitrap_2612': 'Q Exactive HF 2612', - 'Q-Exactive-HF-X-Orbitrap_6016': 'Q Exactive HF-X 6016', - 'Q-Exactive-HF-X-Orbitrap_6004': 'Q Exactive HF-X 6004', - 'Q-Exactive-HF-X-Orbitrap_6075': 'Q Exactive HF-X 6075', - 'Q-Exactive-HF-X-Orbitrap_6078': 'Q Exactive HF-X 6078', - 'Q-Exactive-HF-X-Orbitrap_6070': 'Q Exactive HF-X 6070', - 'Q-Exactive-HF-X-Orbitrap_6071': 'Q Exactive HF-X 6071', - 'Q-Exactive-HF-X-Orbitrap_6011': 'Q Exactive HF-X 6011', - 'Q-Exactive-HF-X-Orbitrap_6073': 'Q Exactive HF-X 6073', - 'Q-Exactive-HF-X-Orbitrap_6101': 'Q Exactive HF-X 6101', - 'Q-Exactive-HF-X-Orbitrap_6096': 'Q Exactive HF-X 6096', - 'Exactive-Series-Orbitrap_6004': 'Exactive Series 6004', - 'Q-Exactive-HF-X-Orbitrap_6043': 'Q Exactive HF-X 6043', - 'Q-Exactive-HF-X-Orbitrap_6025': 'Q Exactive HF-X 6025', - 'Q-Exactive-HF-X-Orbitrap_6022': 'Q Exactive HF-X 6022', - 'Q-Exactive-HF-X-Orbitrap_6023': 'Q Exactive HF-X 6023', - 'Q-Exactive-HF-X-Orbitrap_6028': 'Q Exactive HF-X 6028', - 'Q-Exactive-HF-X-Orbitrap_6013': 'Q Exactive HF-X 6013', - 'Q-Exactive-HF-X-Orbitrap_6044': 'Q Exactive HF-X 6044', - 'Q-Exactive-HF-X-Orbitrap_6324': 'Q Exactive HF-X 6324', - 'Orbitrap-Exploris-480_Invalid_SN_0001': 'Orbitrap Exploris 480 Invalid SN 0001', - 'Orbitrap-Exploris-480_MA10134C': 'Orbitrap Exploris 480 MA10134C', - 'Orbitrap-Exploris-480_MA10132C': 'Orbitrap Exploris 480 MA10132C', - 'Orbitrap-Exploris-480_MA10130C': 'Orbitrap Exploris 480 MA10130C', - 'Orbitrap-Exploris-480_MA10215C': 'Orbitrap Exploris 480 MA10215C'} + 'Q-Exactive-Plus-Orbitrap_1': 'Exactive Plus 1', + 'Q-Exactive-HF-Orbitrap_206': 'Q Exactive HF 206', + 'Q-Exactive-Plus-Orbitrap_143': 'Exactive Plus 143', + 'Q-Exactive-HF-Orbitrap_1': 'Q Exactive HF 1', + 'Q-Exactive-HF-Orbitrap_147': 'Q Exactive HF 147', + 'Q-Exactive-HF-Orbitrap_204': 'Q Exactive HF 204', + 'Q-Exactive-HF-Orbitrap_148': 'Q Exactive HF 148', + 'Q-Exactive-HF-Orbitrap_207': 'Q Exactive HF 207', + 'Q-Exactive-HF-Orbitrap_143': 'Q Exactive HF 143', + 'Orbitrap-Fusion-Lumos_FSN20115': 'Orbitrap Fusion Lumos FSN20115', + 'Q-Exactive-HF-Orbitrap_2612': 'Q Exactive HF 2612', + 'Q-Exactive-HF-X-Orbitrap_6016': 'Q Exactive HF-X 6016', + 'Q-Exactive-HF-X-Orbitrap_6004': 'Q Exactive HF-X 6004', + 'Q-Exactive-HF-X-Orbitrap_6075': 'Q Exactive HF-X 6075', + 'Q-Exactive-HF-X-Orbitrap_6078': 'Q Exactive HF-X 6078', + 'Q-Exactive-HF-X-Orbitrap_6070': 'Q Exactive HF-X 6070', + 'Q-Exactive-HF-X-Orbitrap_6071': 'Q Exactive HF-X 6071', + 'Q-Exactive-HF-X-Orbitrap_6011': 'Q Exactive HF-X 6011', + 'Q-Exactive-HF-X-Orbitrap_6073': 'Q Exactive HF-X 6073', + 'Q-Exactive-HF-X-Orbitrap_6101': 'Q Exactive HF-X 6101', + 'Q-Exactive-HF-X-Orbitrap_6096': 'Q Exactive HF-X 6096', + 'Exactive-Series-Orbitrap_6004': 'Exactive Series 6004', + 'Q-Exactive-HF-X-Orbitrap_6043': 'Q Exactive HF-X 6043', + 'Q-Exactive-HF-X-Orbitrap_6025': 'Q Exactive HF-X 6025', + 'Q-Exactive-HF-X-Orbitrap_6022': 'Q Exactive HF-X 6022', + 'Q-Exactive-HF-X-Orbitrap_6023': 'Q Exactive HF-X 6023', + 'Q-Exactive-HF-X-Orbitrap_6028': 'Q Exactive HF-X 6028', + 'Q-Exactive-HF-X-Orbitrap_6013': 'Q Exactive HF-X 6013', + 'Q-Exactive-HF-X-Orbitrap_6044': 'Q Exactive HF-X 6044', + 'Q-Exactive-HF-X-Orbitrap_6324': 'Q Exactive HF-X 6324', + 'Orbitrap-Exploris-480_Invalid_SN_0001': 'Orbitrap Exploris 480 Invalid SN 0001', + 'Orbitrap-Exploris-480_MA10134C': 'Orbitrap Exploris 480 MA10134C', + 'Orbitrap-Exploris-480_MA10132C': 'Orbitrap Exploris 480 MA10132C', + 'Orbitrap-Exploris-480_MA10130C': 'Orbitrap Exploris 480 MA10130C', + 'Orbitrap-Exploris-480_MA10215C': 'Orbitrap Exploris 480 MA10215C'} df_meta["instrument_label"] = df_meta["instrument_label"].replace(instrument_labels) @@ -126,10 +126,10 @@ counts_instrument = counts_instrument.join( (df_meta - [[*thermo_raw_files.cols_instrument, 'instrument_label']] - .drop_duplicates() - .set_index(thermo_raw_files.cols_instrument) - ) + [[*thermo_raw_files.cols_instrument, 'instrument_label']] + .drop_duplicates() + .set_index(thermo_raw_files.cols_instrument) + ) .set_index('instrument_label', append=True) ) counts_instrument.to_excel( @@ -164,11 +164,11 @@ # %% fig, ax = plt.subplots() ax = (counts_instrument - .plot - .bar( - ax=ax, - ) -) + .plot + .bar( + ax=ax, + ) + ) ax.set_xlabel('') ax.set_ylabel('number of samples (runs)') fname = out_folder / 'number_of_samples_per_instrument.pdf' @@ -197,7 +197,7 @@ ax = (df_meta .loc[mask, cols] .plot - .scatter(cols[0], cols[1], + .scatter(cols[0], cols[1], color='orange', label='normal files', ylabel='filesize (in GB)', @@ -221,7 +221,9 @@ cols = vaep.pandas.get_columns_accessor_from_iterable(cols) view = df_meta.loc[mask_top10_instruments] -view["instrument_label+N"] = view["instrument_label"].replace(counts_instrument.to_frame().apply( lambda s: f"{s.name} (N={s['count']:03d})" , axis=1)) +view["instrument_label+N"] = view["instrument_label"].replace( + counts_instrument.to_frame().apply( + lambda s: f"{s.name} (N={s['count']:03d})", axis=1)) view # %% @@ -241,7 +243,7 @@ title='instrument label', loc='upper right', # alignment='left', -) + ) ax.xaxis.set_major_formatter("{x:,.0f}") ax.yaxis.set_major_formatter("{x:,.0f}") fname = out_folder / 'ms1_to_ms2_top10_instruments.pdf' diff --git a/project/00_4_development_dataset_support.py b/project/00_4_development_dataset_support.py index c6f34a9dd..31c671c70 100644 --- a/project/00_4_development_dataset_support.py +++ b/project/00_4_development_dataset_support.py @@ -20,13 +20,14 @@ import pandas as pd import plotly.express as px -import vaep # set formatting defaults +import vaep # set formatting defaults # %% [markdown] # ## Parameters # %% tags=["parameters"] -support_json: str = 'data\dev_datasets\df_intensities_proteinGroups_long\Q_Exactive_HF_X_Orbitrap_6070_support.json' # Path to json support file +# Path to json support file +support_json: str = 'data\\dev_datasets\\df_intensities_proteinGroups_long\\Q_Exactive_HF_X_Orbitrap_6070_support.json' # %% [markdown] # ## Completeness of samples @@ -36,10 +37,10 @@ support.head() # %% -support.describe(percentiles=np.linspace(0.1,1,10)) +support.describe(percentiles=np.linspace(0.1, 1, 10)) # %% -ax = support.plot(rot=90, figsize=(20,10), legend=False) +ax = support.plot(rot=90, figsize=(20, 10), legend=False) ax.set_ylabel('number of features') ax.yaxis.set_major_formatter("{x:,.0f}") diff --git a/project/00_4_hela_development_dataset_splitting.ipynb b/project/00_4_hela_development_dataset_splitting.ipynb index 2a1a337cf..bdf50a5cd 100644 --- a/project/00_4_hela_development_dataset_splitting.ipynb +++ b/project/00_4_hela_development_dataset_splitting.ipynb @@ -71,10 +71,10 @@ "source": [ "N_MIN_INSTRUMENT = 300\n", "META_DATA: str = 'data/files_selected_metadata.csv'\n", - "FILE_EXT = 'pkl' # 'csv' or 'pkl'\n", + "FILE_EXT = 'pkl' # 'csv' or 'pkl'\n", "SAMPLE_ID = 'Sample ID'\n", "\n", - "DUMP: str = erda_dumps.FN_PROTEIN_GROUPS # Filepath to erda dump\n", + "DUMP: str = erda_dumps.FN_PROTEIN_GROUPS # Filepath to erda dump\n", "OUT_NAME = 'protein group' # for legends labels\n", "# DUMP: str = erda_dumps.FN_PEPTIDES\n", "# OUT_NAME = 'peptide' # for legends labels\n", @@ -181,7 +181,7 @@ "# feat_name = list(data.index.names)\n", "# feat_name.remove(SAMPLE_ID)\n", "feat_name = (OUT_NAME,)\n", - "feat_name # index name(s) which are not the sample index" + "feat_name # index name(s) which are not the sample index" ] }, { @@ -209,7 +209,7 @@ "outputs": [], "source": [ "# sample_ids = data.index.levels[0] # assume first index position is Sample ID?\n", - "sample_ids = data.index.unique() #.get_level_values(SAMPLE_ID).unique() # more explict\n", + "sample_ids = data.index.unique() # .get_level_values(SAMPLE_ID).unique() # more explict\n", "sample_ids" ] }, @@ -258,10 +258,10 @@ "outputs": [], "source": [ "idx_all = (pd.to_datetime(df_meta[\"Content Creation Date\"]).dt.strftime(\"%Y_%m_%d_%H_%M\")\n", - " + '_'\n", - " + df_meta[\"Thermo Scientific instrument model\"].str.replace(' ', '-')\n", - " + '_'\n", - " + df_meta[\"instrument serial number\"].str.split('#').str[-1])\n", + " + '_'\n", + " + df_meta[\"Thermo Scientific instrument model\"].str.replace(' ', '-')\n", + " + '_'\n", + " + df_meta[\"instrument serial number\"].str.split('#').str[-1])\n", "\n", "mask = idx_all.duplicated(keep=False)\n", "duplicated_sample_idx = idx_all.loc[mask].sort_values() # duplicated dumps\n", @@ -276,9 +276,9 @@ "metadata": {}, "outputs": [], "source": [ - "data_duplicates = data.loc[duplicated_sample_idx.index] #.unstack()\n", + "data_duplicates = data.loc[duplicated_sample_idx.index] # .unstack()\n", "# data_duplicates.T.corr() # same samples are have corr. of 1\n", - "data_duplicates.sum(axis=1) # keep only one seems okay" + "data_duplicates.sum(axis=1) # keep only one seems okay" ] }, { @@ -342,7 +342,7 @@ }, "outputs": [], "source": [ - "counts = data.count(axis=1) # wide format\n", + "counts = data.count(axis=1) # wide format\n", "N = len(counts)\n", "fname = FOLDER_DATASETS / 'support_all.json'\n", "files_out[fname.name] = fname\n", @@ -373,7 +373,7 @@ }, "outputs": [], "source": [ - "counts = data.count(axis=0) # wide format\n", + "counts = data.count(axis=0) # wide format\n", "counts.to_json(FOLDER_DATASETS / 'feat_completeness_all.json', indent=4)\n", "ax = (counts\n", " .sort_values() # will raise an error with a DataFrame\n", @@ -592,7 +592,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Summary statistics for top 5 instruments " + "## Summary statistics for top 5 instruments" ] }, { @@ -646,7 +646,7 @@ "metadata": {}, "outputs": [], "source": [ - "top_5_meta = df_meta.loc[mask_top_5] \n", + "top_5_meta = df_meta.loc[mask_top_5]\n", "top_5_meta[['injection volume setting', 'dilution factor']].describe()" ] }, @@ -664,7 +664,7 @@ "outputs": [], "source": [ "for _instrument, _df_meta_instrument in top_5_meta.groupby(by=thermo_raw_files.cols_instrument):\n", - " print('#'* 80, ' - '.join(_instrument), sep='\\n')\n", + " print('#' * 80, ' - '.join(_instrument), sep='\\n')\n", " display(_df_meta_instrument.describe())\n", " display(_df_meta_instrument['injection volume setting'].value_counts())\n", " break" @@ -728,7 +728,7 @@ "\n", " # calculate support\n", " counts = dataset.count(axis=1).squeeze()\n", - " ## to disk\n", + " # to disk\n", " fname_support = vaep.io.get_fname_from_keys(values,\n", " folder='.',\n", " file_ext=\"\")\n", @@ -736,7 +736,7 @@ " (fname_support.stem + '_support.json').replace('Exactive_Series_slot_#', ''))\n", " files_out[fname_support.name] = fname_support\n", " logger.info(f\"Dump support to: {fname_support.as_posix()}\")\n", - " \n", + "\n", " counts.to_json(fname_support, indent=4)\n", "\n", " # very slow alternative, but 100% correct\n", @@ -757,7 +757,7 @@ " ))\n", " vaep.plotting.add_prop_as_second_yaxis(ax, M)\n", " fig.tight_layout()\n", - " fname_support = fname_support.with_suffix('.pdf') \n", + " fname_support = fname_support.with_suffix('.pdf')\n", " files_out[fname_support.name] = fname_support\n", " vaep.plotting.savefig(fig, name=fname_support)" ] diff --git a/project/00_4_hela_development_dataset_splitting.py b/project/00_4_hela_development_dataset_splitting.py index bafc8dac3..5cba7438c 100644 --- a/project/00_4_hela_development_dataset_splitting.py +++ b/project/00_4_hela_development_dataset_splitting.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -54,10 +54,10 @@ # %% tags=["parameters"] N_MIN_INSTRUMENT = 300 META_DATA: str = 'data/files_selected_metadata.csv' -FILE_EXT = 'pkl' # 'csv' or 'pkl' +FILE_EXT = 'pkl' # 'csv' or 'pkl' SAMPLE_ID = 'Sample ID' -DUMP: str = erda_dumps.FN_PROTEIN_GROUPS # Filepath to erda dump +DUMP: str = erda_dumps.FN_PROTEIN_GROUPS # Filepath to erda dump OUT_NAME = 'protein group' # for legends labels # DUMP: str = erda_dumps.FN_PEPTIDES # OUT_NAME = 'peptide' # for legends labels @@ -118,7 +118,7 @@ # feat_name = list(data.index.names) # feat_name.remove(SAMPLE_ID) feat_name = (OUT_NAME,) -feat_name # index name(s) which are not the sample index +feat_name # index name(s) which are not the sample index # %% # M = len(data.index.levels[-1]) @@ -130,7 +130,7 @@ # %% # sample_ids = data.index.levels[0] # assume first index position is Sample ID? -sample_ids = data.index.unique() #.get_level_values(SAMPLE_ID).unique() # more explict +sample_ids = data.index.unique() # .get_level_values(SAMPLE_ID).unique() # more explict sample_ids # %% [markdown] @@ -151,10 +151,10 @@ # - drop metadata (entire) # %% idx_all = (pd.to_datetime(df_meta["Content Creation Date"]).dt.strftime("%Y_%m_%d_%H_%M") - + '_' - + df_meta["Thermo Scientific instrument model"].str.replace(' ', '-') - + '_' - + df_meta["instrument serial number"].str.split('#').str[-1]) + + '_' + + df_meta["Thermo Scientific instrument model"].str.replace(' ', '-') + + '_' + + df_meta["instrument serial number"].str.split('#').str[-1]) mask = idx_all.duplicated(keep=False) duplicated_sample_idx = idx_all.loc[mask].sort_values() # duplicated dumps @@ -162,9 +162,9 @@ # # %% -data_duplicates = data.loc[duplicated_sample_idx.index] #.unstack() +data_duplicates = data.loc[duplicated_sample_idx.index] # .unstack() # data_duplicates.T.corr() # same samples are have corr. of 1 -data_duplicates.sum(axis=1) # keep only one seems okay +data_duplicates.sum(axis=1) # keep only one seems okay # %% idx_unique = idx_all.drop_duplicates() @@ -191,7 +191,7 @@ # ## Support per sample in entire data set # %% -counts = data.count(axis=1) # wide format +counts = data.count(axis=1) # wide format N = len(counts) fname = FOLDER_DATASETS / 'support_all.json' files_out[fname.name] = fname @@ -215,7 +215,7 @@ # %% -counts = data.count(axis=0) # wide format +counts = data.count(axis=0) # wide format counts.to_json(FOLDER_DATASETS / 'feat_completeness_all.json', indent=4) ax = (counts .sort_values() # will raise an error with a DataFrame @@ -358,7 +358,7 @@ vaep.savefig(fig, name=fname) # %% [markdown] -# ## Summary statistics for top 5 instruments +# ## Summary statistics for top 5 instruments # %% fig, ax = plt.subplots(1, 1, figsize=(6, 6)) @@ -399,7 +399,7 @@ # %% -top_5_meta = df_meta.loc[mask_top_5] +top_5_meta = df_meta.loc[mask_top_5] top_5_meta[['injection volume setting', 'dilution factor']].describe() # %% [markdown] @@ -407,7 +407,7 @@ # %% for _instrument, _df_meta_instrument in top_5_meta.groupby(by=thermo_raw_files.cols_instrument): - print('#'* 80, ' - '.join(_instrument), sep='\n') + print('#' * 80, ' - '.join(_instrument), sep='\n') display(_df_meta_instrument.describe()) display(_df_meta_instrument['injection volume setting'].value_counts()) break @@ -455,7 +455,7 @@ # calculate support counts = dataset.count(axis=1).squeeze() - ## to disk + # to disk fname_support = vaep.io.get_fname_from_keys(values, folder='.', file_ext="") @@ -463,7 +463,7 @@ (fname_support.stem + '_support.json').replace('Exactive_Series_slot_#', '')) files_out[fname_support.name] = fname_support logger.info(f"Dump support to: {fname_support.as_posix()}") - + counts.to_json(fname_support, indent=4) # very slow alternative, but 100% correct @@ -484,7 +484,7 @@ )) vaep.plotting.add_prop_as_second_yaxis(ax, M) fig.tight_layout() - fname_support = fname_support.with_suffix('.pdf') + fname_support = fname_support.with_suffix('.pdf') files_out[fname_support.name] = fname_support vaep.plotting.savefig(fig, name=fname_support) diff --git a/project/00_6_0_permute_data.ipynb b/project/00_6_0_permute_data.ipynb index d8b6493db..c16637bc1 100644 --- a/project/00_6_0_permute_data.ipynb +++ b/project/00_6_0_permute_data.ipynb @@ -23,6 +23,7 @@ "import numpy as np\n", "import vaep\n", "import vaep.analyzers.analyzers\n", + "from vaep.utils import create_random_df\n", "\n", "logger = vaep.logging.setup_nb_logger()\n", "logger.info(\"Split data and make diagnostic plots\")" @@ -35,7 +36,6 @@ "metadata": {}, "outputs": [], "source": [ - "from vaep.utils import create_random_df\n", "t = create_random_df(N=10, M=3)\n", "t = t.apply(lambda x: np.arange(len(x)))\n", "t" @@ -77,12 +77,11 @@ }, "outputs": [], "source": [ - "FN_INTENSITIES: str = 'data/dev_datasets/df_intensities_proteinGroups_long/Q_Exactive_HF_X_Orbitrap_6070.pkl' # Sample (rows) intensiites for features (columns)\n", - "index_col: Union[str, int] = 0 # Can be either a string or position (typical 0 for first column), or a list of these.\n", - "# wide_format: bool = False # intensities in wide format (more memory efficient of csv). Default is long_format (more precise)\n", - "column_names: List[str] = [\"Gene Names\"] # Manuelly set column names (of Index object in columns)\n", - "out_folder: str = '' # Output folder for permuted data, optional. Default is to save with suffix '_permuted' in same folder as input data\n", - "random_seed: int = 42 # Random seed for reproducibility\n", + "FN_INTENSITIES: str = 'data/dev_datasets/df_intensities_proteinGroups_long/Q_Exactive_HF_X_Orbitrap_6070.pkl' # Sample (rows) intensiites for features (columns)\n", + "index_col: Union[str, int] = 0 # Can be either a string or position (typical 0 for first column), or a list of these.\n", + "column_names: List[str] = [\"Gene Names\"] # Manuelly set column names (of Index object in columns)\n", + "out_folder: str = '' # Output folder for permuted data, optional. Default is to save with suffix '_permuted' in same folder as input data\n", + "random_seed: int = 42 # Random seed for reproducibility\n", "file_format: str = 'pkl'" ] }, @@ -149,9 +148,9 @@ "\n", "\n", "FILE_FORMAT_TO_CONSTRUCTOR_IN = {'csv': 'from_csv',\n", - " 'pkl': 'from_pickle',\n", - " 'pickle': 'from_pickle',\n", - " }\n", + " 'pkl': 'from_pickle',\n", + " 'pickle': 'from_pickle',\n", + " }\n", "\n", "FILE_EXT = Path(args.FN_INTENSITIES).suffix[1:]\n", "logger.info(f\"File format (extension): {FILE_EXT} (!specifies data loading function!)\")" @@ -168,10 +167,10 @@ "source": [ "constructor = getattr(\n", " vaep.analyzers.analyzers.AnalyzePeptides,\n", - " FILE_FORMAT_TO_CONSTRUCTOR_IN[FILE_EXT]) #AnalyzePeptides.from_csv \n", + " FILE_FORMAT_TO_CONSTRUCTOR_IN[FILE_EXT]) # AnalyzePeptides.from_csv\n", "analysis = constructor(fname=args.FN_INTENSITIES,\n", - " index_col=args.index_col,\n", - " )" + " index_col=args.index_col,\n", + " )" ] }, { @@ -215,7 +214,7 @@ "\n", "method = getattr(df, FILE_FORMAT_TO_CONSTRUCTOR.get(FILE_EXT))\n", "\n", - "fname = vaep.utils.append_to_filepath(args.FN_INTENSITIES , 'permuted')\n", + "fname = vaep.utils.append_to_filepath(args.FN_INTENSITIES, 'permuted')\n", "method(fname)" ] }, @@ -228,10 +227,10 @@ "source": [ "constructor = getattr(\n", " vaep.analyzers.analyzers.AnalyzePeptides,\n", - " FILE_FORMAT_TO_CONSTRUCTOR_IN[FILE_EXT]) #AnalyzePeptides.from_csv \n", + " FILE_FORMAT_TO_CONSTRUCTOR_IN[FILE_EXT]) # AnalyzePeptides.from_csv\n", "analysis = constructor(fname=args.FN_INTENSITIES,\n", - " index_col=args.index_col,\n", - " )" + " index_col=args.index_col,\n", + " )" ] } ], @@ -257,7 +256,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.17" } }, "nbformat": 4, diff --git a/project/00_6_0_permute_data.py b/project/00_6_0_permute_data.py index bc33b0774..9c6612d2e 100644 --- a/project/00_6_0_permute_data.py +++ b/project/00_6_0_permute_data.py @@ -9,12 +9,12 @@ import numpy as np import vaep import vaep.analyzers.analyzers +from vaep.utils import create_random_df logger = vaep.logging.setup_nb_logger() logger.info("Split data and make diagnostic plots") # %% -from vaep.utils import create_random_df t = create_random_df(N=10, M=3) t = t.apply(lambda x: np.arange(len(x))) t @@ -30,12 +30,11 @@ # %% tags=["parameters"] -FN_INTENSITIES: str = 'data/dev_datasets/df_intensities_proteinGroups_long/Q_Exactive_HF_X_Orbitrap_6070.pkl' # Sample (rows) intensiites for features (columns) -index_col: Union[str, int] = 0 # Can be either a string or position (typical 0 for first column), or a list of these. -# wide_format: bool = False # intensities in wide format (more memory efficient of csv). Default is long_format (more precise) -column_names: List[str] = ["Gene Names"] # Manuelly set column names (of Index object in columns) -out_folder: str = '' # Output folder for permuted data, optional. Default is to save with suffix '_permuted' in same folder as input data -random_seed: int = 42 # Random seed for reproducibility +FN_INTENSITIES: str = 'data/dev_datasets/df_intensities_proteinGroups_long/Q_Exactive_HF_X_Orbitrap_6070.pkl' # Sample (rows) intensiites for features (columns) +index_col: Union[str, int] = 0 # Can be either a string or position (typical 0 for first column), or a list of these. +column_names: List[str] = ["Gene Names"] # Manuelly set column names (of Index object in columns) +out_folder: str = '' # Output folder for permuted data, optional. Default is to save with suffix '_permuted' in same folder as input data +random_seed: int = 42 # Random seed for reproducibility file_format: str = 'pkl' # %% @@ -63,9 +62,9 @@ FILE_FORMAT_TO_CONSTRUCTOR_IN = {'csv': 'from_csv', - 'pkl': 'from_pickle', - 'pickle': 'from_pickle', - } + 'pkl': 'from_pickle', + 'pickle': 'from_pickle', + } FILE_EXT = Path(args.FN_INTENSITIES).suffix[1:] logger.info(f"File format (extension): {FILE_EXT} (!specifies data loading function!)") @@ -73,10 +72,10 @@ # %% constructor = getattr( vaep.analyzers.analyzers.AnalyzePeptides, - FILE_FORMAT_TO_CONSTRUCTOR_IN[FILE_EXT]) #AnalyzePeptides.from_csv + FILE_FORMAT_TO_CONSTRUCTOR_IN[FILE_EXT]) # AnalyzePeptides.from_csv analysis = constructor(fname=args.FN_INTENSITIES, - index_col=args.index_col, - ) + index_col=args.index_col, + ) # %% @@ -95,12 +94,12 @@ method = getattr(df, FILE_FORMAT_TO_CONSTRUCTOR.get(FILE_EXT)) -fname = vaep.utils.append_to_filepath(args.FN_INTENSITIES , 'permuted') +fname = vaep.utils.append_to_filepath(args.FN_INTENSITIES, 'permuted') method(fname) # %% constructor = getattr( vaep.analyzers.analyzers.AnalyzePeptides, - FILE_FORMAT_TO_CONSTRUCTOR_IN[FILE_EXT]) #AnalyzePeptides.from_csv + FILE_FORMAT_TO_CONSTRUCTOR_IN[FILE_EXT]) # AnalyzePeptides.from_csv analysis = constructor(fname=args.FN_INTENSITIES, - index_col=args.index_col, - ) + index_col=args.index_col, + ) diff --git a/project/00_6_hela_training_data_exploration.ipynb b/project/00_6_hela_training_data_exploration.ipynb index ab393060d..856f3919d 100644 --- a/project/00_6_hela_training_data_exploration.ipynb +++ b/project/00_6_hela_training_data_exploration.ipynb @@ -2,159 +2,103 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "Collapsed": "false" + }, "source": [ - "# Inspect data using plots\n", - "- spread of intensities between samples\n", - "- spread of intensities within samples\n", - "- missing data plots: violin, box and histogram - both for features and samples\n", - " - optionally: plot proposed cutoffs (on per default)\n", - "- correlation analysis: can linear correlation be picked up?\n", - "-\n", + "# Peptides\n", "\n", - "Does not save filtered data, this is done by splitting notebook. Only visualisations." + "Load peptides selected for training" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "from __future__ import annotations\n", - "import json\n", + "from datetime import datetime\n", + "from functools import partial\n", "from pathlib import Path\n", + "from random import sample\n", "\n", + "import ipywidgets as w\n", "import numpy as np\n", "import pandas as pd\n", + "import matplotlib\n", "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", "\n", - "import matplotlib\n", + "# from sklearn import preprocessing\n", + "# from sklearn.decomposition import PCA\n", + "import seaborn as sns\n", "\n", "import vaep\n", - "from vaep import plotting\n", - "from vaep.pandas import missing_data\n", - "import vaep.data_handling\n", + "from vaep.data_handling import coverage\n", + "from vaep.plotting import _savefig\n", + "\n", + "import config\n", "from vaep.analyzers import analyzers\n", + "from vaep.io.data_objects import PeptideCounter\n", + "from vaep.transform import log\n", + "\n", + "pd.options.display.max_columns = 100\n", + "pd.options.display.min_rows = 30" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Descriptive Statistics (Linear case)\n", "\n", - "logger = vaep.logging.setup_nb_logger()\n", - "\n", - "matplotlib.rcParams.update({'font.size': 5,\n", - " 'figure.figsize': [4.0, 2.0]})\n", - "\n", - "\n", - "def only_every_x_ticks(ax, x=2, axis=None):\n", - " \"\"\"Sparse out ticks on both axis by factor x\"\"\"\n", - " if axis is None:\n", - " ax.set_xticks(ax.get_xticks()[::x])\n", - " ax.set_yticks(ax.get_yticks()[::x])\n", - " else:\n", - " if axis == 0:\n", - " ax.set_xticks(ax.get_xticks()[::x])\n", - " elif axis == 1:\n", - " ax.set_yticks(ax.get_yticks()[::x])\n", - " else:\n", - " raise ValueError(f'axis must be 0 or 1, got {axis}')\n", - " return ax\n", - "\n", - "\n", - "def use_first_n_chars_in_labels(ax, x=2):\n", - " \"\"\"Take first N characters of labels and use them as new labels\"\"\"\n", - " # xaxis\n", - " _new_labels = [l.get_text()[:x]\n", - " for l in ax.get_xticklabels()]\n", - " _ = ax.set_xticklabels(_new_labels)\n", - " # yaxis\n", - " _new_labels = [l.get_text()[:x] for l in ax.get_yticklabels()]\n", - " _ = ax.set_yticklabels(_new_labels)\n", - " return ax\n", - "\n", - "\n", - "def split_xticklabels(ax, PG_SEPARATOR=';'):\n", - " \"\"\"Split labels by PG_SEPARATOR and only use first part\"\"\"\n", - " if PG_SEPARATOR is not None:\n", - " _new_labels = [l.get_text().split(PG_SEPARATOR)[0]\n", - " for l in ax.get_xticklabels()]\n", - " _ = ax.set_xticklabels(_new_labels)\n", - " return ax\n", - "\n", - "\n", - "def get_clustermap(data,\n", - " figsize=(8, 8),\n", - " cbar_pos: tuple[float, float, float, float] = (\n", - " 0.02, 0.83, 0.03, 0.15),\n", - " **kwargs):\n", - " from sklearn.impute import SimpleImputer\n", - " from vaep.pandas import _add_indices\n", - " X = SimpleImputer().fit_transform(data)\n", - " X = _add_indices(X, data)\n", - " cg = sns.clustermap(X,\n", - " z_score=0,\n", - " cmap=\"vlag\",\n", - " center=0,\n", - " cbar_pos=cbar_pos,\n", - " figsize=figsize,\n", - " **kwargs\n", - " )\n", - " return cg\n", - "\n", - "\n", - "def get_dynamic_range(min_max):\n", - " dynamic_range = pd.DataFrame(range(*min_max), columns=['x'])\n", - " dynamic_range['$2^x$'] = dynamic_range.x.apply(lambda x: 2**x)\n", - " dynamic_range.set_index('x', inplace=True)\n", - " dynamic_range.index.name = ''\n", - " dynamic_range = dynamic_range.T\n", - " return dynamic_range" + "- spread of peptide quantifications between samples\n", + "- spread of quantifications within samples\n", + "- correlation analysis: can linear correlation be picked up?\n" ] }, { "cell_type": "markdown", + "id": "8b4a827b", "metadata": {}, "source": [ - "## Parameters" + "### Peptides" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "lines_to_next_cell": 2, - "tags": [ - "parameters" - ] - }, + "metadata": {}, + "outputs": [], + "source": [ + "FN_PEPTIDE_INTENSITIES = Path(\n", + " 'data/dev_datasets/df_intensities_proteinGroups_long_2017_2018_2019_2020_N05015_M04547/Q_Exactive_HF_X_Orbitrap_Exactive_Series_slot_#6070.csv')\n", + "FIGUREFOLDER = FN_PEPTIDE_INTENSITIES.parent / 'figures' / FN_PEPTIDE_INTENSITIES.stem\n", + "FIGUREFOLDER.mkdir(exist_ok=True, parents=True)\n", + "FIGUREFOLDER" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "858f0520", + "metadata": {}, "outputs": [], "source": [ - "FN_INTENSITIES: str = 'data/dev_datasets/HeLa_6070/protein_groups_wide_N50.csv'\n", - "FOLDER_EXPERIMENT: str = 'runs/example/data_inspection'\n", "N_FIRST_ROWS = None # possibility to select N first rows\n", - "LOG_TRANSFORM: bool = True # log transform data\n", - "# list of integers or string denoting the index columns (used for csv)\n", - "INDEX_COL: list = [0]\n", - "COL_INDEX_NAME: str = 'Protein groups' # name of column index, can be None\n", - "LONG_FORMAT: bool = False # if True, the data is expected to be in long format\n", - "# Threshold used later for data filtering (here only for visualisation)\n", - "COMPLETENESS_OVER_SAMPLES = 0.25 # 25% of samples have to have that features\n", - "MIN_FEAT_PER_SAMPLE = .4 # 40% of features selected in first step\n", - "# protein group separator, e.g.';' (could also be gene groups)\n", - "PG_SEPARATOR: str = ';'\n", - "SAMPLE_FIRST_N_CHARS: int = 16 # number of characters used for sample names\n", - "# if True, do not use tick on heatmap - only label\n", - "NO_TICK_LABELS_ON_HEATMAP: bool = True" + "analysis = analyzers.AnalyzePeptides.from_csv(fname=FN_PEPTIDE_INTENSITIES, index_col=[0, 1], nrows=N_FIRST_ROWS)\n", + "df = analysis.to_wide_format()\n", + "analysis.describe_peptides(sample_n=30)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Load and check data\n", + "### Peptide frequency: sellect the N most common peptides\n", "\n", - "- supported for now: pickle and comma separated\n", - "- transform long to wide data?\n", - "- log transform data using logarithm of two?\n", - "- remove entirely missing columns (features) or rows (samples)" + "- N most common peptides between samples" ] }, { @@ -163,29 +107,20 @@ "metadata": {}, "outputs": [], "source": [ - "FOLDER_EXPERIMENT = Path(FOLDER_EXPERIMENT)\n", - "FN_INTENSITIES = Path(FN_INTENSITIES)\n", + "N = 10\n", "\n", - "FIGUREFOLDER = FOLDER_EXPERIMENT / 'figures'\n", - "FIGUREFOLDER.mkdir(exist_ok=True, parents=True)\n", - "FIGUREFOLDER\n", - "\n", - "files_out = dict()" + "peptide_counter = PeptideCounter(config.FNAME_C_PEPTIDES)\n", + "peptide_counter.counter.most_common(N)" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "lines_to_next_cell": 0 - }, + "metadata": {}, "outputs": [], "source": [ - "if FN_INTENSITIES.suffix == '.pkl':\n", - " data = pd.read_pickle(FN_INTENSITIES)\n", - "elif FN_INTENSITIES.suffix == '.csv':\n", - " data = pd.read_csv(FN_INTENSITIES, index_col=INDEX_COL, nrows=N_FIRST_ROWS)\n", - "data" + "counts = analysis.df.count().sort_values(ascending=False)\n", + "counts.iloc[:N]" ] }, { @@ -194,47 +129,44 @@ "metadata": {}, "outputs": [], "source": [ - "if LONG_FORMAT:\n", - " data = data.squeeze().unstack()\n", - "if LOG_TRANSFORM:\n", - " data = np.log2(data).astype(float)\n", - "\n", - "\n", - "# drop entrily missing rows or columns\n", - "data = data.dropna(axis=0, how='all').dropna(axis=1, how='all')\n", - "data" + "analysis.df[counts.iloc[:N].index]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Correlation between peptides\n", + "- linear correlation as indicator that there is some variation which could be used by models (or other heuristics)" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "lines_to_next_cell": 2 - }, + "metadata": {}, "outputs": [], "source": [ - "if len(data.columns.names) > 1:\n", - " _levels_dropped = data.columns.names[1:]\n", - " data.columns = data.columns.droplevel(_levels_dropped)\n", - " logger.warning(\"Drop multiindex level, kepp only first. Dropped: \"\n", - " f\"{_levels_dropped}\")\n", - "# allows overwriting of index name, also to None\n", - "data.columns.name = COL_INDEX_NAME" + "sample = analysis.df.sample(n=30, axis=1)\n", + "# ToDo func is assigned to df\n", + "corr_lower_triangle = analyzers.corr_lower_triangle(sample)\n", + "corr_lower_triangle" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, + "id": "826033b0", "metadata": {}, + "outputs": [], "source": [ - "## Calculate cutoffs for visualization and stats" + "fig, axes = analyzers.plot_corr_histogram(corr_lower_triangle, bins=40)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "- filtering based on many other samples?\n", - "- low feature completeness threshold in comparison to other approaches" + "### Samples" ] }, { @@ -243,12 +175,14 @@ "metadata": {}, "outputs": [], "source": [ - "min_samples_per_feat = int(len(data) * COMPLETENESS_OVER_SAMPLES)\n", - "print(f\"{min_samples_per_feat = }\")\n", - "mask = data.notna().sum(axis=0) > min_samples_per_feat\n", - "print(f\"drop = {(~mask).sum()} features\")\n", - "selected = data.loc[:, mask]\n", - "selected.shape" + "analysis.df.sample(30, axis=0).T.describe()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Peptides (all)" ] }, { @@ -257,70 +191,74 @@ "metadata": {}, "outputs": [], "source": [ - "min_feat_per_sample = int(selected.shape[-1] * MIN_FEAT_PER_SAMPLE)\n", - "print(f\"{min_feat_per_sample = }\")\n", - "samples_selected = selected.notna().sum(axis=1) >= min_feat_per_sample\n", - "print(f\"drop = {(~samples_selected).sum()} samples\")\n", - "selected = selected[samples_selected]\n", - "selected.shape" + "stats = analysis.describe_peptides()" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, + "id": "f0b01a33", "metadata": {}, + "outputs": [], "source": [ - "### Update records if cutoffs would be used" + "# biological coefficient of variation: standard deviation (variation) w.r.t mean\n", + "_ = stats.loc['CV'].hist(figsize=(10, 4))" ] }, { "cell_type": "code", "execution_count": null, + "id": "1e84e975", "metadata": {}, "outputs": [], "source": [ - "records = dict(inital=missing_data.get_record(data))\n", - "records" + "_ = stats.loc['count'].hist(figsize=(10, 4))" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "id": "8dca5410", + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "records.update(\n", - " dict(filtered=missing_data.get_record(selected)))\n", - "records.update({'params':\n", - " dict(MIN_FEAT_PER_SAMPLE=float(MIN_FEAT_PER_SAMPLE),\n", - " COMPLETENESS_OVER_SAMPLES=float(\n", - " COMPLETENESS_OVER_SAMPLES),\n", - " min_feat_per_sample=int(min_feat_per_sample),\n", - " min_samples_per_feat=int(min_samples_per_feat),)\n", - " })\n", - "records" + "INDEX_NAME = 'Sample ID'\n", + "analysis.df.index.name = INDEX_NAME" ] }, { "cell_type": "code", "execution_count": null, + "id": "0da26061", "metadata": { - "lines_to_next_cell": 2 + "Collapsed": "false" }, "outputs": [], "source": [ - "fname = FOLDER_EXPERIMENT / 'records.json'\n", - "files_out[fname.name] = fname\n", - "with open(fname, 'w') as f:\n", - " json.dump(records, f, indent=4)" + "analysis.df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60215da2", + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "N_MIN_OBS = analysis.df.shape[0] * 0.7 # here: present in 70% of the samples\n", + "mask_min_obsevation = analysis.df.notna().sum() >= N_MIN_OBS\n", + "mask_min_obsevation.sum()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Plot basic distribution present-absent pattern of features and samples\n", - "\n", - "### Line plots" + "Reference analysis.df as `X`" ] }, { @@ -329,59 +267,77 @@ "metadata": {}, "outputs": [], "source": [ - "fig = plotting.data.plot_missing_dist_highdim(data,\n", - " min_feat_per_sample=min_feat_per_sample,\n", - " min_samples_per_feat=min_samples_per_feat)\n", - "fname = FIGUREFOLDER / f'dist_all_lineplot_w_cutoffs.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname)" + "X = analysis.df" + ] + }, + { + "cell_type": "markdown", + "id": "c9f1411e", + "metadata": { + "Collapsed": "false" + }, + "source": [ + "## Completeness of peptides" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "fig = plotting.data.plot_missing_dist_highdim(data)\n", - "fname = FIGUREFOLDER / f'dist_all_lineplot_wo_cutoffs.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname)" + "%time not_missing = vaep.data_handling.get_sorted_not_missing(X)\n", + "not_missing.iloc[:, -10:].describe()" ] }, { "cell_type": "code", "execution_count": null, - "id": "f891da5c", - "metadata": {}, + "id": "d83e6998", + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "fig = plotting.data.plot_missing_pattern_histogram(data,\n", - " min_feat_per_sample=min_feat_per_sample,\n", - " min_samples_per_feat=min_samples_per_feat)\n", - "fname = FIGUREFOLDER / f'dist_all_histogram_w_cutoffs.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname)" + "sample_completeness = not_missing.sum(axis=1).sort_values() / X.shape[-1]\n", + "sample_completeness" ] }, { "cell_type": "code", "execution_count": null, - "id": "1f38e2d9", - "metadata": {}, + "id": "b70f867c", + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "fig = plotting.data.plot_missing_pattern_histogram(data)\n", - "fname = FIGUREFOLDER / f'dist_all_histogram_wo_cutoffs.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname)" + "N_MOST_COMMON_PEPTIDES = 300\n", + "data_to_visualize = not_missing.iloc[:, -N_MOST_COMMON_PEPTIDES:]\n", + "data_to_visualize = data_to_visualize.loc[sample_completeness.index]\n", + "print(f\"Look at missingness pattern of {N_MOST_COMMON_PEPTIDES} most common peptides across sample.\\n\"\n", + " f\"Data matrix dimension used for printing: { data_to_visualize.shape}\")\n", + "\n", + "\n", + "fig_heatmap_missing, axes_heatmap_missing = plt.subplots(\n", + " 1, 1, figsize=(12, 8))\n", + "USE_CBAR = False\n", + "\n", + "axes_heatmap_missing = sns.heatmap(data_to_visualize,\n", + " ax=axes_heatmap_missing,\n", + " cbar=USE_CBAR,\n", + " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Boxplots" + "White patches indicates that a peptide has been measured, black means it was not measured. Some samples (rows) have few of the most common peptides. This suggests to set a minimum of total peptides in a sample, which is common pratice.\n", + "\n", + "> An algorithm should work with the most common peptides and base it's inference capabilities after training on these." ] }, { @@ -390,371 +346,530 @@ "metadata": {}, "outputs": [], "source": [ - "fig = plotting.data.plot_missing_dist_boxplots(data)\n", - "fname = FIGUREFOLDER / f'dist_all_boxplots.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname)" + "data_to_visualize.sum(axis=1).nsmallest(20) # Samplest with the fewest measurements out of the seletion" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "# # This currently crashes if you want to have a pdf\n", + "datetime_now = datetime.now()\n", + "_savefig = partial(_savefig, folder=FIGUREFOLDER)\n", + "\n", + "_savefig(fig_heatmap_missing,\n", + " f'peptides_heatmap_missing_{datetime_now:%y%m%d}', pdf=False)" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "Collapsed": "false" + }, "source": [ - "### Violinplots" + "## Sample stats" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "fig = plotting.data.plot_missing_pattern_violinplot(\n", - " data, min_feat_per_sample, min_samples_per_feat)\n", - "fname = FIGUREFOLDER / f'dist_all_violin_plot.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname)" + "TYPE = 'peptides'\n", + "COL_NO_MISSING, COL_NO_IDENTIFIED = f'no_missing_{TYPE}', f'no_identified_{TYPE}'\n", + "COL_PROP_SAMPLES = 'prop_samples'\n", + "\n", + "\n", + "sample_stats = vaep.data_handling.compute_stats_missing(not_missing, COL_NO_MISSING, COL_NO_IDENTIFIED)\n", + "sample_stats" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": { - "lines_to_next_cell": 0 + "Collapsed": "false" }, + "outputs": [], "source": [ - "## Feature medians over prop. of missing of feature" + "fig_ident = sns.relplot(\n", + " x='SampleID_int', y=COL_NO_IDENTIFIED, data=sample_stats)\n", + "fig_ident.set_axis_labels('Sample ID', f'Frequency of identified {TYPE}')\n", + "fig_ident.fig.suptitle(f'Frequency of identified {TYPE} by sample id', y=1.03)\n", + "_savefig(fig_ident, f'identified_{TYPE}_by_sample', folder=FIGUREFOLDER)\n", + "\n", + "fig_ident_dist = sns.relplot(\n", + " x=COL_PROP_SAMPLES, y=COL_NO_IDENTIFIED, data=sample_stats)\n", + "fig_ident_dist.set_axis_labels(\n", + " 'Proportion of samples (sorted by frequency)', f'Frequency of identified {TYPE}')\n", + "fig_ident_dist.fig.suptitle(\n", + " f'Frequency of identified {TYPE} groups by sample id', y=1.03)\n", + "_savefig(fig_ident_dist, f'identified_{TYPE}_ordered', folder=FIGUREFOLDER)" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "ax = plotting.data.plot_feat_median_over_prop_missing(\n", - " data=data, type='scatter', s=1)\n", - "fname = FIGUREFOLDER / 'intensity_median_vs_prop_missing_scatter'\n", - "files_out[fname.stem] = fname\n", - "vaep.savefig(ax.get_figure(), fname)" + "COL_NO_MISSING_PROP = COL_NO_MISSING + '_PROP'\n", + "sample_stats[COL_NO_MISSING_PROP] = sample_stats[COL_NO_MISSING] / \\\n", + " float(X.shape[1])\n", + "\n", + "# from ggplot import *\n", + "# ggplot(aes(x='nan_proc'), data = nonnan) + geom_histogram(binwidth = 0.005) #+ ylim(0,0.025)\n", + "sns.set(style=\"darkgrid\")\n", + "g = sns.relplot(x='prop_samples', y=COL_NO_MISSING_PROP, data=sample_stats)\n", + "plt.subplots_adjust(top=0.9)\n", + "g.set_axis_labels(\n", + " \"Proportion of samples (sorted by frequency)\", \"proportion missing\")\n", + "g.fig.suptitle(f'Proportion of missing {TYPE} ordered')\n", + "_savefig(g, \"proportion_proteins_missing\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "Collapsed": "false" + }, + "source": [ + "## Look at sequences\n", + "\n", + "Shows mainly that from a 6-7 AA on, peptides sequences are nearly unique.\n", + "\n", + "> Overlapping peptides (from the start or the end) could still be interesting to find" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "lines_to_next_cell": 2 + "Collapsed": "false" }, "outputs": [], "source": [ - "ax = plotting.data.plot_feat_median_over_prop_missing(\n", - " data=data, type='boxplot', s=.8)\n", - "fname = FIGUREFOLDER / 'intensity_median_vs_prop_missing_boxplot'\n", - "files_out[fname.stem] = fname\n", - "vaep.savefig(ax.get_figure(), fname)" + "class SequenceAnalyser():\n", + "\n", + " def __init__(self, sequences: pd.Series):\n", + " if not isinstance(sequences, pd.Series):\n", + " raise ValueError(\n", + " \"Please provide a pandas.Series, not {}\".format(type(sequences)))\n", + " self.sequences = sequences\n", + "\n", + " def calc_counts(self, n_characters):\n", + " return self.sequences.str[:n_characters].value_counts()\n", + "\n", + " def length(self):\n", + " return self.sequences.str.len().sort_values()" ] }, { - "cell_type": "markdown", - "metadata": {}, + "cell_type": "code", + "execution_count": null, + "metadata": { + "Collapsed": "false" + }, + "outputs": [], "source": [ - "## Correlation between peptides\n", - "- linear correlation as indicator that there is some variation which could be used by models (or other heuristics)" + "sequences = SequenceAnalyser(X.columns.to_series())\n", + "sequences.length()" ] }, { "cell_type": "code", "execution_count": null, + "id": "b7979950", "metadata": { - "lines_to_next_cell": 2 + "Collapsed": "false" }, "outputs": [], "source": [ - "%%time\n", - "corr_lower_triangle = analyzers.corr_lower_triangle(data)\n", - "fig, axes = analyzers.plot_corr_histogram(corr_lower_triangle, bins=40)\n", - "fname = FIGUREFOLDER / f'corr_histogram_feat.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname)" + "_ = w.interact(sequences.calc_counts,\n", + " n_characters=w.IntSlider(value=4, min=1, max=55))" ] }, { - "cell_type": "markdown", - "metadata": {}, + "cell_type": "code", + "execution_count": null, + "id": "431b9221", + "metadata": { + "Collapsed": "false" + }, + "outputs": [], "source": [ - "### Coefficient of variation (CV) of features" + "sequences_p4 = sequences.calc_counts(4)\n", + "display(sequences_p4.head())" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "id": "a00e631b", + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "cv = data.std() / data.mean()\n", - "# biological coefficient of variation: standard deviation (variation) w.r.t mean\n", - "ax = cv.hist(bins=30)\n", - "fname = FIGUREFOLDER / f'CV_histogram_features.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(ax.get_figure(), name=fname)" + "sequences_p4.loc[sequences_p4.isin(('CON_', 'REV_'))].sort_index()" ] }, { "cell_type": "markdown", - "metadata": {}, + "id": "0bc4e272", + "metadata": { + "Collapsed": "false" + }, + "source": [ + "What to do when\n", + "\n", + "\n", + "```\n", + "AAAAAAAAAAGAAGGRGSGPGR\n", + "AAAAAAAAAAGAAGGRGSGPGRR\n", + "\n", + "AAAANSGSSLPLFDCPTWAGKPPPGLHLDVVK\n", + "AAAANSGSSLPLFDCPTWAGKPPPGLHLDVVKGDK\n", + "```\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "821af58a", + "metadata": { + "Collapsed": "false" + }, + "source": [ + "## Select Training Data" + ] + }, + { + "cell_type": "markdown", + "id": "e83f0238", + "metadata": { + "Collapsed": "false" + }, "source": [ - "## Clustermap and heatmaps of missing values" + "### Minumum required sample quality\n", + "First define the minum requirement of a sample to be kept in" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "id": "b2517983", + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "# needs to deal with duplicates\n", - "# notna = data.notna().T.drop_duplicates().T\n", - "# get index and column names\n", - "cg = sns.clustermap(data.notna(), cbar_pos=None)\n", - "ax = cg.ax_heatmap\n", - "if PG_SEPARATOR is not None:\n", - " _new_labels = [l.get_text().split(PG_SEPARATOR)[0]\n", - " for l in ax.get_xticklabels()]\n", - " _ = ax.set_xticklabels(_new_labels)\n", - "if NO_TICK_LABELS_ON_HEATMAP:\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - "fname = FIGUREFOLDER / 'clustermap_present_absent_pattern.png'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(cg.fig,\n", - " name=fname,\n", - " pdf=False)" + "range_peps = (0, max(sample_stats[COL_NO_IDENTIFIED]))\n", + "MIN_DEPTH_SAMPLE = int(range_peps[1] * 0.6)\n", + "w_min_depth_sample = w.IntSlider(\n", + " value=MIN_DEPTH_SAMPLE, min=0, max=range_peps[1])\n", + "print(f'Minimum {TYPE} per sample observed:')\n", + "w_min_depth_sample" ] }, { - "cell_type": "markdown", - "metadata": {}, + "cell_type": "code", + "execution_count": null, + "id": "d4b59bd2", + "metadata": { + "Collapsed": "false" + }, + "outputs": [], "source": [ - "based on cluster, plot heatmaps of features and samples" + "mask_samples = sample_stats[COL_NO_IDENTIFIED] >= w_min_depth_sample.value\n", + "print(f\"Selected {mask_samples.sum()} samples\")" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "id": "e75668aa", + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "assert (len(cg.dendrogram_row.reordered_ind), len(\n", - " cg.dendrogram_col.reordered_ind)) == data.shape" + "x_50 = coverage(X.loc[mask_samples], coverage_col=0.5, coverage_row=0.2)\n", + "# x_50_pca = log_z_zeroone_na(x_50) # there is a huge difference if NA is set to low value or mean!!\n", + "x_90 = coverage(X.loc[mask_samples], 0.9, 0.9)" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "id": "1e3135a6", + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "vaep.plotting.make_large_descriptors(5)\n", - "ax = sns.heatmap(\n", - " data.iloc[cg.dendrogram_row.reordered_ind,\n", - " cg.dendrogram_col.reordered_ind],\n", - ")\n", - "only_every_x_ticks(ax, x=2)\n", - "use_first_n_chars_in_labels(ax, x=SAMPLE_FIRST_N_CHARS)\n", - "if PG_SEPARATOR is not None:\n", - " _new_labels = [l.get_text().split(PG_SEPARATOR)[0]\n", - " for l in ax.get_xticklabels()]\n", - " _ = ax.set_xticklabels(_new_labels)\n", - "if NO_TICK_LABELS_ON_HEATMAP:\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - "fname = FIGUREFOLDER / 'heatmap_intensities_ordered_by_missing_pattern.png'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(ax.get_figure(), name=fname, pdf=False)\n", - "# ax.get_figure().savefig(fname, dpi=300)" + "x_50.shape, x_90.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f5be5099", + "metadata": { + "Collapsed": "false" + }, + "outputs": [], + "source": [ + "x_90.sample()" ] }, { "cell_type": "markdown", + "id": "df2816dd", "metadata": {}, "source": [ - "### Heatmap of sample and feature correlation" + "Data selection should be done for each experiment, so it is not resaved here" ] }, { "cell_type": "code", "execution_count": null, + "id": "864cc51c", "metadata": {}, "outputs": [], "source": [ - "fig, ax = plt.subplots(figsize=(4, 4))\n", - "ax = sns.heatmap(\n", - " analyzers.corr_lower_triangle(\n", - " data.iloc[:, cg.dendrogram_col.reordered_ind]),\n", - " ax=ax,\n", - " square=True,\n", - ")\n", - "_ = only_every_x_ticks(ax, x=2)\n", - "_ = use_first_n_chars_in_labels(ax, x=SAMPLE_FIRST_N_CHARS)\n", - "if PG_SEPARATOR is not None:\n", - " _new_labels = [l.get_text().split(PG_SEPARATOR)[0]\n", - " for l in ax.get_xticklabels()]\n", - " _ = ax.set_xticklabels(_new_labels)\n", - "if NO_TICK_LABELS_ON_HEATMAP:\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - "fname = FIGUREFOLDER / 'heatmap_feature_correlation.png'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname, pdf=False)" + "#from vaep.io.data_objects import get_fname\n", + "# fname = config.FOLDER_DATA / get_fname(*x_90.shape)\n", + "# print(fname)\n", + "# x_90.to_csv(fname)\n", + "# fname = config.FOLDER_DATA / get_fname(*x_50.shape)\n", + "# print(fname)\n", + "# x_50.to_csv(fname)" + ] + }, + { + "cell_type": "markdown", + "id": "3d8ea98b", + "metadata": { + "Collapsed": "false" + }, + "source": [ + "### Distribution of Intensity values\n", + "- comparing non-transformed to $\\log_{10}$ transformed\n", + "- log transformation makes data more normal distributed\n", + "\n", + "> log10 or log2 or ln" + ] + }, + { + "cell_type": "markdown", + "id": "6a9f9f88", + "metadata": {}, + "source": [ + "#### Sample with all peptides" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "id": "cd813441", + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "fig, ax = plt.subplots(figsize=(4, 4))\n", - "ax = sns.heatmap(\n", - " analyzers.corr_lower_triangle(\n", - " data.T.iloc[:, cg.dendrogram_row.reordered_ind]),\n", - " ax=ax,\n", - " square=True,\n", - ")\n", - "_ = only_every_x_ticks(ax, x=2)\n", - "_ = use_first_n_chars_in_labels(ax, x=SAMPLE_FIRST_N_CHARS)\n", - "if NO_TICK_LABELS_ON_HEATMAP:\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - "fname = FIGUREFOLDER / 'heatmap_sample_correlation.png'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname, pdf=False)" + "sample = x_50.sample().iloc[0]\n", + "sample_id = sample.name\n", + "print(\"Sample ID:\", sample_id)" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "id": "83097013", + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "kwargs = dict()\n", - "if NO_TICK_LABELS_ON_HEATMAP:\n", - " kwargs['xticklabels'] = False\n", - " kwargs['yticklabels'] = False\n", - "cg = get_clustermap(data, **kwargs)\n", - "ax = cg.ax_heatmap\n", - "if PG_SEPARATOR is not None:\n", - " _new_labels = [l.get_text().split(PG_SEPARATOR)[0]\n", - " for l in ax.get_xticklabels()]\n", - " _ = ax.set_xticklabels(_new_labels)\n", - "_ = only_every_x_ticks(ax, x=2, axis=0)\n", - "_ = use_first_n_chars_in_labels(ax, x=SAMPLE_FIRST_N_CHARS)\n", "\n", - "fname = FIGUREFOLDER / 'clustermap_intensities_normalized.png'\n", - "files_out[fname.name] = fname\n", - "cg.fig.savefig(fname, dpi=300) # avoid tight_layout\n", - "# tight_layout makes the cbar a bit ugly\n", - "# vaep.savefig(cg.fig,\n", - "# name=fname,\n", - "# pdf=False)" + "sns.set(style=\"darkgrid\")\n", + "\n", + "\n", + "def plot_dist_comparison(\n", + " sample: pd.Series, figsize=(12, 5),\n", + " log=np.log, log_name=None,\n", + ") -> matplotlib.figure.Figure:\n", + " fig, axes = plt.subplots(1, 2, figsize=figsize)\n", + "\n", + " sns.histplot(sample, bins=100, ax=axes[0])\n", + " axes[0].set_title(\"Unnormalized distribution\")\n", + "\n", + " sample_log = log(sample)\n", + " sns.histplot(sample_log, bins=100, ax=axes[1])\n", + " if not log_name:\n", + " log_name = str(log).split(\"'\")[1]\n", + " axes[1].set_title(f\"{log_name} normalized distribution\")\n", + " sample_id = sample.name\n", + " _ = fig.suptitle(f\"Dynamic Range of measured intensities in sample {sample_id}\")\n", + " fig.tight_layout(rect=[0, 0.03, 1, 0.95])\n", + " return fig\n", + "\n", + "\n", + "fig = plot_dist_comparison(sample)\n", + "_savefig(fig, f\"distribution_sample_peptides_{str(sample_id)}_ln\")" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, + "id": "cbcff3de", "metadata": {}, + "outputs": [], "source": [ - "## Sample stats" + "fig = plot_dist_comparison(sample, log=np.log2)\n", + "_savefig(fig, f\"distribution_peptides_sample_{str(sample_id)}_log2\")" ] }, { "cell_type": "code", "execution_count": null, + "id": "46fea6ba", "metadata": {}, "outputs": [], "source": [ - "TYPE = 'feat'\n", - "COL_NO_MISSING, COL_NO_IDENTIFIED = f'no_missing_{TYPE}', f'no_identified_{TYPE}'\n", - "COL_PROP_SAMPLES = 'prop_samples'\n", - "\n", - "sample_stats = vaep.data_handling.compute_stats_missing(\n", - " data.notna(), COL_NO_MISSING, COL_NO_IDENTIFIED)\n", - "sample_stats" + "sample_log_stats = np.log2(sample).describe().to_frame('log2')\n", + "sample_log_stats['ln'] = np.log(sample).describe()\n", + "sample_log_stats" ] }, { "cell_type": "code", "execution_count": null, + "id": "6e1f2979", "metadata": {}, "outputs": [], "source": [ - "fig_ident = sns.relplot(\n", - " x='SampleID_int', y=COL_NO_IDENTIFIED, data=sample_stats)\n", - "fig_ident.set_axis_labels('Sample ID', f'Frequency of identified {TYPE}')\n", - "fig_ident.fig.suptitle(f'Frequency of identified {TYPE} by sample id', y=1.03)\n", - "vaep.savefig(fig_ident, f'identified_{TYPE}_by_sample', folder=FIGUREFOLDER)\n", + "print(f\"Factor for log2 to ln: {1 / np.log2(np.e) = :.3f}\")\n", + "c = 1 / np.log2(np.e)" + ] + }, + { + "cell_type": "markdown", + "id": "1de60bb5", + "metadata": {}, + "source": [ + "If $ log2(x) \\sim \\mathcal{N}\\big(\\mu_{log2}, \\sigma_{log2}^2 \\big) $, then $ ln(x) \\sim \\mathcal{N}\\big(0.693 \\cdot \\mu_{log2}, 0.693^2 \\cdot \\sigma_{log2}^2 \\big) $.\n", "\n", - "fig_ident_dist = sns.relplot(\n", - " x=COL_PROP_SAMPLES, y=COL_NO_IDENTIFIED, data=sample_stats)\n", - "fig_ident_dist.set_axis_labels(\n", - " 'Proportion of samples (sorted by frequency)', f'Frequency of identified {TYPE}')\n", - "fig_ident_dist.fig.suptitle(\n", - " f'Frequency of identified {TYPE} groups by sample id', y=1.03)\n", - "fname = FIGUREFOLDER / f'identified_{TYPE}_ordered.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig_ident_dist, fname)" + "> Question: Is a wider or narrower distribtion important, or does only be \"normal\"" ] }, { "cell_type": "code", "execution_count": null, + "id": "a233ca42", "metadata": {}, "outputs": [], "source": [ - "COL_NO_MISSING_PROP = COL_NO_MISSING + '_PROP'\n", - "sample_stats[COL_NO_MISSING_PROP] = sample_stats[COL_NO_MISSING] / \\\n", - " float(data.shape[1])\n", - "sns.set(style=\"white\")\n", - "g = sns.relplot(x='prop_samples', y=COL_NO_MISSING_PROP, data=sample_stats)\n", - "plt.subplots_adjust(top=0.9)\n", - "plt.ylim(0, 1)\n", - "g.set_axis_labels(\n", - " \"Proportion of samples (sorted by frequency)\", \"proportion missing\")\n", - "g.fig.suptitle(f'Proportion of missing {TYPE} ordered')\n", - "\n", - "fname = FIGUREFOLDER / 'proportion_feat_missing.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(g, fname)" + "print(f\"mean: {sample_log_stats.loc['mean','log2'] * c = : .3f}\")\n", + "print(f\"std : {sample_log_stats.loc['std' ,'log2'] * c = : .3f}\")" ] }, { "cell_type": "markdown", + "id": "fb999f0b", "metadata": {}, "source": [ - "### Reference table intensities (log2)" + "#### One Peptide, all samples" ] }, { "cell_type": "code", "execution_count": null, + "id": "495cd93c", "metadata": { - "lines_to_next_cell": 2 + "Collapsed": "false" }, "outputs": [], "source": [ - "min_max = int(data.min().min()), int(data.max().max()) + 1\n", - "dynamic_range = None\n", - "if min_max[1] < 100:\n", - " dynamic_range = get_dynamic_range(min_max)\n", - "dynamic_range" + "sample = x_50.sample(axis=1).squeeze()\n", + "peptide = sample.name\n", + "\n", + "fig = plot_dist_comparison(sample)\n", + "_savefig(fig, f\"distribution_peptide_samples_{str(peptide)}_ln\")" + ] + }, + { + "cell_type": "markdown", + "id": "56898125", + "metadata": { + "Collapsed": "false" + }, + "source": [ + "### Reference table intensities (natural logarithm)\n", + "\n", + "14 to 23 spans a dynamic range of 3 orders of base 10" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "id": "8b08e367", + "metadata": { + "Collapsed": "false" + }, "outputs": [], "source": [ - "files_out" + "dynamic_range = pd.DataFrame(range(14, 24), columns=['x'])\n", + "dynamic_range['$e^x$'] = dynamic_range.x.apply(np.exp)\n", + "dynamic_range.set_index('x', inplace=True)\n", + "dynamic_range.index.name = ''\n", + "dynamic_range.T" ] + }, + { + "cell_type": "markdown", + "id": "6d57a983", + "metadata": { + "Collapsed": "false" + }, + "source": [ + "## Next UP" + ] + }, + { + "cell_type": "markdown", + "id": "0bc1af1f", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "id": "9a6a80d7", + "metadata": { + "Collapsed": "false" + }, + "source": [ + "### Find Protein of Peptides\n", + "- check with some reference list of peptides: This is created in `project\\FASTA_tryptic_digest.ipynb`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7abf7a7f", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/project/00_6_hela_training_data_exploration.py b/project/00_6_hela_training_data_exploration.py index 913a81401..84cc616fc 100644 --- a/project/00_6_hela_training_data_exploration.py +++ b/project/00_6_hela_training_data_exploration.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: vaep # language: python @@ -21,9 +21,12 @@ from datetime import datetime from functools import partial from pathlib import Path +from random import sample +import ipywidgets as w import numpy as np import pandas as pd +import matplotlib import matplotlib.pyplot as plt # from sklearn import preprocessing @@ -37,6 +40,7 @@ import config from vaep.analyzers import analyzers from vaep.io.data_objects import PeptideCounter +from vaep.transform import log pd.options.display.max_columns = 100 pd.options.display.min_rows = 30 @@ -53,14 +57,15 @@ # ### Peptides # %% -FN_PEPTIDE_INTENSITIES = Path('data/dev_datasets/df_intensities_proteinGroups_long_2017_2018_2019_2020_N05015_M04547/Q_Exactive_HF_X_Orbitrap_Exactive_Series_slot_#6070.csv') +FN_PEPTIDE_INTENSITIES = Path( + 'data/dev_datasets/df_intensities_proteinGroups_long_2017_2018_2019_2020_N05015_M04547/Q_Exactive_HF_X_Orbitrap_Exactive_Series_slot_#6070.csv') FIGUREFOLDER = FN_PEPTIDE_INTENSITIES.parent / 'figures' / FN_PEPTIDE_INTENSITIES.stem FIGUREFOLDER.mkdir(exist_ok=True, parents=True) FIGUREFOLDER # %% -N_FIRST_ROWS = None # possibility to select N first rows -analysis = analyzers.AnalyzePeptides.from_csv(fname=FN_PEPTIDE_INTENSITIES, index_col=[0,1],nrows=N_FIRST_ROWS) +N_FIRST_ROWS = None # possibility to select N first rows +analysis = analyzers.AnalyzePeptides.from_csv(fname=FN_PEPTIDE_INTENSITIES, index_col=[0, 1], nrows=N_FIRST_ROWS) df = analysis.to_wide_format() analysis.describe_peptides(sample_n=30) @@ -108,10 +113,11 @@ stats = analysis.describe_peptides() # %% -_ = stats.loc['CV'].hist(figsize=(10, 4)) # biological coefficient of variation: standard deviation (variation) w.r.t mean +# biological coefficient of variation: standard deviation (variation) w.r.t mean +_ = stats.loc['CV'].hist(figsize=(10, 4)) # %% -_ = stats.loc['count'].hist(figsize=(10,4)) +_ = stats.loc['count'].hist(figsize=(10, 4)) # %% Collapsed="false" INDEX_NAME = 'Sample ID' @@ -121,7 +127,7 @@ analysis.df # %% Collapsed="false" -N_MIN_OBS = analysis.df.shape[0] * 0.7 # here: present in 70% of the samples +N_MIN_OBS = analysis.df.shape[0] * 0.7 # here: present in 70% of the samples mask_min_obsevation = analysis.df.notna().sum() >= N_MIN_OBS mask_min_obsevation.sum() @@ -156,16 +162,16 @@ axes_heatmap_missing = sns.heatmap(data_to_visualize, ax=axes_heatmap_missing, - cbar = USE_CBAR, - ) + cbar=USE_CBAR, + ) # %% [markdown] -# White patches indicates that a peptide has been measured, black means it was not measured. Some samples (rows) have few of the most common peptides. This suggests to set a minimum of total peptides in a sample, which is common pratice. +# White patches indicates that a peptide has been measured, black means it was not measured. Some samples (rows) have few of the most common peptides. This suggests to set a minimum of total peptides in a sample, which is common pratice. # # > An algorithm should work with the most common peptides and base it's inference capabilities after training on these. # %% -data_to_visualize.sum(axis=1).nsmallest(20) # Samplest with the fewest measurements out of the seletion +data_to_visualize.sum(axis=1).nsmallest(20) # Samplest with the fewest measurements out of the seletion # %% Collapsed="false" # # This currently crashes if you want to have a pdf @@ -184,7 +190,7 @@ COL_PROP_SAMPLES = 'prop_samples' -sample_stats = vaep.data_handling.compute_stats_missing(not_missing, COL_NO_MISSING, COL_NO_IDENTIFIED ) +sample_stats = vaep.data_handling.compute_stats_missing(not_missing, COL_NO_MISSING, COL_NO_IDENTIFIED) sample_stats # %% Collapsed="false" @@ -246,9 +252,8 @@ def length(self): sequences.length() # %% Collapsed="false" -import ipywidgets as w _ = w.interact(sequences.calc_counts, - n_characters=w.IntSlider(value=4, min=1, max=55)) + n_characters=w.IntSlider(value=4, min=1, max=55)) # %% Collapsed="false" sequences_p4 = sequences.calc_counts(4) @@ -258,7 +263,7 @@ def length(self): sequences_p4.loc[sequences_p4.isin(('CON_', 'REV_'))].sort_index() # %% [markdown] Collapsed="false" -# What to do when +# What to do when # # # ``` @@ -276,11 +281,10 @@ def length(self): # %% [markdown] Collapsed="false" # ### Minumum required sample quality -# First define the minum requirement of a sample to be kept in +# First define the minum requirement of a sample to be kept in # %% Collapsed="false" -import ipywidgets as w -range_peps = (0, max(sample_stats[COL_NO_IDENTIFIED])) +range_peps = (0, max(sample_stats[COL_NO_IDENTIFIED])) MIN_DEPTH_SAMPLE = int(range_peps[1] * 0.6) w_min_depth_sample = w.IntSlider( value=MIN_DEPTH_SAMPLE, min=0, max=range_peps[1]) @@ -326,11 +330,10 @@ def length(self): # %% Collapsed="false" sample = x_50.sample().iloc[0] -sample_id = sample.name +sample_id = sample.name print("Sample ID:", sample_id) # %% Collapsed="false" -import matplotlib sns.set(style="darkgrid") @@ -363,8 +366,8 @@ def plot_dist_comparison( _savefig(fig, f"distribution_peptides_sample_{str(sample_id)}_log2") # %% -sample_log_stats = np.log2(sample).describe().to_frame('log2') -sample_log_stats['ln'] = np.log (sample).describe() +sample_log_stats = np.log2(sample).describe().to_frame('log2') +sample_log_stats['ln'] = np.log(sample).describe() sample_log_stats # %% @@ -384,8 +387,6 @@ def plot_dist_comparison( # #### One Peptide, all samples # %% Collapsed="false" -from vaep.transform import log -from random import sample sample = x_50.sample(axis=1).squeeze() peptide = sample.name @@ -412,6 +413,6 @@ def plot_dist_comparison( # %% [markdown] Collapsed="false" # ### Find Protein of Peptides -# - check with some reference list of peptides: This is created in `project\FASTA_tryptic_digest.ipynb` +# - check with some reference list of peptides: This is created in `project\FASTA_tryptic_digest.ipynb` # %% diff --git a/project/01_0_transform_data_to_wide_format.ipynb b/project/01_0_transform_data_to_wide_format.ipynb index f8ccd842c..4d5266a1d 100644 --- a/project/01_0_transform_data_to_wide_format.ipynb +++ b/project/01_0_transform_data_to_wide_format.ipynb @@ -145,7 +145,7 @@ "source": [ "fname = params.data / 'sample_annotation_placeholder.csv'\n", "annotation.to_csv(fname)\n", - "fname " + "fname" ] }, { @@ -164,14 +164,15 @@ "cell_type": "code", "execution_count": null, "id": "ce749fdb", - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ "fname = params.data / 'data_wide_sample_cols.csv'\n", - "# fillna('Filtered') \n", + "# fillna('Filtered')\n", "train_data.T.to_csv(fname)\n", - "fname\n", - "\n" + "fname" ] }, { diff --git a/project/01_0_transform_data_to_wide_format.py b/project/01_0_transform_data_to_wide_format.py index 7fe6f7293..b23bf8154 100644 --- a/project/01_0_transform_data_to_wide_format.py +++ b/project/01_0_transform_data_to_wide_format.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -70,18 +70,17 @@ # %% fname = params.data / 'sample_annotation_placeholder.csv' annotation.to_csv(fname) -fname +fname # %% [markdo] # Save with samples in columns # %% fname = params.data / 'data_wide_sample_cols.csv' -# fillna('Filtered') +# fillna('Filtered') train_data.T.to_csv(fname) fname - # %% # 'data_wide_sample_cols.csv' diff --git a/project/01_1_train_CF.ipynb b/project/01_1_train_CF.ipynb index f67d3e710..d0fba2b54 100644 --- a/project/01_1_train_CF.ipynb +++ b/project/01_1_train_CF.ipynb @@ -15,7 +15,10 @@ "metadata": {}, "outputs": [], "source": [ + "\n", + "\n", "import logging\n", + "\n", "from pprint import pprint\n", "\n", "from fastai.basics import *\n", @@ -26,22 +29,23 @@ "from fastai.tabular.all import *\n", "from fastai.collab import *\n", "\n", - "# overwriting Recorder callback with custom plot_loss\n", - "from vaep.models import plot_loss, RecorderDump\n", - "from fastai import learner\n", - "learner.Recorder.plot_loss = plot_loss\n", - "# import fastai.callback.hook # Learner.summary\n", - "\n", - "\n", "import vaep\n", "import vaep.model\n", "import vaep.models as models\n", - "from vaep.io import datasplits\n", - "from vaep import sampling\n", - "\n", + "from vaep.models import plot_loss, RecorderDump\n", "\n", "import vaep.nb\n", + "from vaep import sampling\n", + "from vaep.io import datasplits\n", + "\n", "from vaep.logging import setup_logger\n", + "\n", + "# overwriting Recorder callback with custom plot_loss\n", + "from fastai import learner\n", + "learner.Recorder.plot_loss = plot_loss\n", + "# import fastai.callback.hook # Learner.summary\n", + "\n", + "\n", "logger = setup_logger(logger=logging.getLogger('vaep'))\n", "logger.info(\n", " \"Experiment 03 - Analysis of latent spaces and performance comparisions\")\n", @@ -96,7 +100,7 @@ "# model\n", "# Dimensionality of encoding dimension (latent space of model)\n", "latent_dim: int = 10\n", - "# hidden_layers:str = '128_64' # A space separated string of layers, '50 20' for the encoder, reverse will be use for decoder\n", + "# hidden_layers:str = '128_64' # Underscore separated string of layers, '128 64' for the encoder, reversed for decoder\n", "sample_idx_position: int = 0 # position of index which is sample ID\n", "model: str = 'CF' # model name\n", "model_key: str = 'CF' # potentially alternative key for model (grid search)\n", @@ -201,6 +205,17 @@ "data.train_X.sample(5)" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3311709", + "metadata": {}, + "outputs": [], + "source": [ + "! add check that specified data is available\n", + "# silent error in fastai if e.g. target column is not available" + ] + }, { "cell_type": "markdown", "id": "6045414b", @@ -344,7 +359,7 @@ " target_column='intensity',\n", " model_kwargs=dict(n_factors=args.latent_dim,\n", " y_range=(int(data.train_X.min()),\n", - " int(data.train_X.max())+1)\n", + " int(data.train_X.max()) + 1)\n", " ),\n", " batch_size=args.batch_size)" ] @@ -586,7 +601,9 @@ "source": [ "### Test Datasplit\n", "\n", - "Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction." + "Fake NAs : Artificially created NAs. Some data was sampled and set\n", + "explicitly to misssing before it was fed to the model for\n", + "reconstruction." ] }, { diff --git a/project/01_1_train_CF.py b/project/01_1_train_CF.py index 642bcb02a..de18d7276 100644 --- a/project/01_1_train_CF.py +++ b/project/01_1_train_CF.py @@ -17,7 +17,10 @@ # # Collaborative Filtering # %% + + import logging + from pprint import pprint from fastai.basics import * @@ -28,22 +31,23 @@ from fastai.tabular.all import * from fastai.collab import * -# overwriting Recorder callback with custom plot_loss -from vaep.models import plot_loss, RecorderDump -from fastai import learner -learner.Recorder.plot_loss = plot_loss -# import fastai.callback.hook # Learner.summary - - import vaep import vaep.model import vaep.models as models -from vaep.io import datasplits -from vaep import sampling - +from vaep.models import plot_loss, RecorderDump import vaep.nb +from vaep import sampling +from vaep.io import datasplits + from vaep.logging import setup_logger + +# overwriting Recorder callback with custom plot_loss +from fastai import learner +learner.Recorder.plot_loss = plot_loss +# import fastai.callback.hook # Learner.summary + + logger = setup_logger(logger=logging.getLogger('vaep')) logger.info( "Experiment 03 - Analysis of latent spaces and performance comparisions") @@ -75,7 +79,7 @@ # model # Dimensionality of encoding dimension (latent space of model) latent_dim: int = 10 -# hidden_layers:str = '128_64' # A space separated string of layers, '50 20' for the encoder, reverse will be use for decoder +# hidden_layers:str = '128_64' # Underscore separated string of layers, '128 64' for the encoder, reversed for decoder sample_idx_position: int = 0 # position of index which is sample ID model: str = 'CF' # model name model_key: str = 'CF' # potentially alternative key for model (grid search) @@ -122,6 +126,10 @@ # %% data.train_X.sample(5) +# %% +# ! add check that specified data is available +# silent error in fastai if e.g. target column is not available + # %% [markdown] # Infer index names from long format @@ -192,7 +200,7 @@ target_column='intensity', model_kwargs=dict(n_factors=args.latent_dim, y_range=(int(data.train_X.min()), - int(data.train_X.max())+1) + int(data.train_X.max()) + 1) ), batch_size=args.batch_size) @@ -317,7 +325,9 @@ # %% [markdown] # ### Test Datasplit # -# Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction. +# Fake NAs : Artificially created NAs. Some data was sampled and set +# explicitly to misssing before it was fed to the model for +# reconstruction. # %% added_metrics = d_metrics.add_metrics(test_pred_fake_na, 'test_fake_na') diff --git a/project/01_1_train_DAE.ipynb b/project/01_1_train_DAE.ipynb index 01f3397db..f8991e229 100644 --- a/project/01_1_train_DAE.ipynb +++ b/project/01_1_train_DAE.ipynb @@ -24,30 +24,31 @@ "from fastai.callback.all import *\n", "from fastai.torch_basics import *\n", "\n", + "import sklearn\n", + "from sklearn.preprocessing import StandardScaler\n", + "from sklearn.impute import SimpleImputer\n", + "\n", + "import vaep\n", + "from vaep import sampling\n", + "from vaep.io import datasplits\n", + "from vaep.models import ae\n", + "import vaep.models as models\n", + "import vaep.model\n", + "from vaep.analyzers import analyzers\n", + "\n", "# overwriting Recorder callback with custom plot_loss\n", "from vaep.models import plot_loss\n", "from fastai import learner\n", + "\n", "learner.Recorder.plot_loss = plot_loss\n", "# import fastai.callback.hook # Learner.summary\n", "\n", - "import sklearn\n", - "from sklearn.impute import SimpleImputer\n", - "from sklearn.preprocessing import StandardScaler\n", - "from sklearn.preprocessing import MinMaxScaler\n", "\n", - "import vaep\n", - "from vaep.analyzers import analyzers\n", - "import vaep.model\n", - "import vaep.models as models\n", - "from vaep.models import ae\n", "# from vaep.models import collab as vaep_collab\n", "# from vaep.io.datasets import DatasetWithTarget\n", "# from vaep.transform import VaepPipeline\n", - "from vaep.io import datasplits\n", "# from vaep.io.dataloaders import get_dls, get_test_dl\n", - "from vaep import sampling\n", "\n", - "import vaep.nb as config\n", "logger = vaep.logging.setup_logger(logging.getLogger('vaep'))\n", "logger.info(\n", " \"Experiment 03 - Analysis of latent spaces and performance comparisions\")\n", @@ -470,7 +471,9 @@ "id": "35704935-c739-48f5-9912-1c1ab1e6c4d3", "metadata": {}, "source": [ - "Adding a `EarlyStoppingCallback` results in an error. Potential fix in [PR3509](https://github.com/fastai/fastai/pull/3509) is not yet in current version. Try again later" + "Adding a `EarlyStoppingCallback` results in an error. Potential fix in\n", + "[PR3509](https://github.com/fastai/fastai/pull/3509) is not yet in\n", + "current version. Try again later" ] }, { @@ -776,7 +779,9 @@ "source": [ "### Test Datasplit\n", "\n", - "Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction." + "Fake NAs : Artificially created NAs. Some data was sampled and set\n", + "explicitly to misssing before it was fed to the model for\n", + "reconstruction." ] }, { diff --git a/project/01_1_train_DAE.py b/project/01_1_train_DAE.py index f336a1d30..afe60065f 100644 --- a/project/01_1_train_DAE.py +++ b/project/01_1_train_DAE.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -24,30 +24,31 @@ from fastai.callback.all import * from fastai.torch_basics import * +import sklearn +from sklearn.preprocessing import StandardScaler +from sklearn.impute import SimpleImputer + +import vaep +from vaep import sampling +from vaep.io import datasplits +from vaep.models import ae +import vaep.models as models +import vaep.model +from vaep.analyzers import analyzers + # overwriting Recorder callback with custom plot_loss from vaep.models import plot_loss from fastai import learner + learner.Recorder.plot_loss = plot_loss # import fastai.callback.hook # Learner.summary -import sklearn -from sklearn.impute import SimpleImputer -from sklearn.preprocessing import StandardScaler -from sklearn.preprocessing import MinMaxScaler -import vaep -from vaep.analyzers import analyzers -import vaep.model -import vaep.models as models -from vaep.models import ae # from vaep.models import collab as vaep_collab # from vaep.io.datasets import DatasetWithTarget # from vaep.transform import VaepPipeline -from vaep.io import datasplits # from vaep.io.dataloaders import get_dls, get_test_dl -from vaep import sampling -import vaep.nb as config logger = vaep.logging.setup_logger(logging.getLogger('vaep')) logger.info( "Experiment 03 - Analysis of latent spaces and performance comparisions") @@ -257,7 +258,9 @@ analysis.learn.show_training_loop() # %% [markdown] -# Adding a `EarlyStoppingCallback` results in an error. Potential fix in [PR3509](https://github.com/fastai/fastai/pull/3509) is not yet in current version. Try again later +# Adding a `EarlyStoppingCallback` results in an error. Potential fix in +# [PR3509](https://github.com/fastai/fastai/pull/3509) is not yet in +# current version. Try again later # %% # learn.summary() @@ -393,7 +396,9 @@ # %% [markdown] # ### Test Datasplit # -# Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction. +# Fake NAs : Artificially created NAs. Some data was sampled and set +# explicitly to misssing before it was fed to the model for +# reconstruction. # %% added_metrics = d_metrics.add_metrics(test_pred_fake_na, 'test_fake_na') diff --git a/project/01_1_train_Median.ipynb b/project/01_1_train_Median.ipynb index ab7e1965c..3c2933e5d 100644 --- a/project/01_1_train_Median.ipynb +++ b/project/01_1_train_Median.ipynb @@ -66,17 +66,17 @@ "outputs": [], "source": [ "# files and folders\n", - "folder_experiment:str = 'runs/example' # Datasplit folder with data for experiment\n", - "file_format: str = 'csv' # file format of create splits, default pickle (pkl)\n", - "fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv' # Machine parsed metadata from rawfile workflow\n", + "folder_experiment: str = 'runs/example' # Datasplit folder with data for experiment\n", + "file_format: str = 'csv' # file format of create splits, default pickle (pkl)\n", + "fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv' # Metadata for samples\n", "# model\n", - "sample_idx_position: int = 0 # position of index which is sample ID\n", - "model_key: str = 'Median' # model key (lower cased version will be used for file names)\n", - "model: str = 'Median' # model name\n", - "save_pred_real_na: bool = True # Save all predictions for real na\n", + "sample_idx_position: int = 0 # position of index which is sample ID\n", + "model_key: str = 'Median' # model key (lower cased version will be used for file names)\n", + "model: str = 'Median' # model name\n", + "save_pred_real_na: bool = True # Save all predictions for real na\n", "# metadata -> defaults for metadata extracted from machine data\n", - "meta_date_col: str = None # date column in meta data\n", - "meta_cat_col: str = None # category column in meta data" + "meta_date_col: str = None # date column in meta data\n", + "meta_cat_col: str = None # category column in meta data" ] }, { @@ -146,7 +146,7 @@ "metadata": {}, "outputs": [], "source": [ - "data = datasplits.DataSplits.from_folder(args.data, file_format=args.file_format) " + "data = datasplits.DataSplits.from_folder(args.data, file_format=args.file_format)" ] }, { @@ -172,7 +172,7 @@ "id": "fa7dcd09", "metadata": {}, "source": [ - "Infer index names from long format " + "Infer index names from long format" ] }, { @@ -184,7 +184,7 @@ "source": [ "index_columns = list(data.train_X.index.names)\n", "sample_id = index_columns.pop(args.sample_idx_position)\n", - "if len(index_columns) == 1: \n", + "if len(index_columns) == 1:\n", " index_column = index_columns.pop()\n", " index_columns = None\n", " logger.info(f\"{sample_id = }, single feature: {index_column = }\")\n", @@ -241,7 +241,7 @@ "outputs": [], "source": [ "freq_feat = vaep.io.datasplits.load_freq(args.data)\n", - "freq_feat.head() # training data" + "freq_feat.head() # training data" ] }, { @@ -257,7 +257,7 @@ "id": "23ac9141", "metadata": {}, "source": [ - "The validation fake NA is used to by all models to evaluate training performance. " + "The validation fake NA is used to by all models to evaluate training performance." ] }, { @@ -275,12 +275,13 @@ "cell_type": "code", "execution_count": null, "id": "68ea1649", - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ "test_pred_fake_na = data.test_y.to_frame(name='observed')\n", - "test_pred_fake_na.describe()\n", - "\n" + "test_pred_fake_na.describe()" ] }, { @@ -322,7 +323,7 @@ "metadata": {}, "outputs": [], "source": [ - "# interpolated = vaep.pandas.interpolate(wide_df = data.train_X) \n", + "# interpolated = vaep.pandas.interpolate(wide_df = data.train_X)\n", "# val_pred_fake_na['interpolated'] = interpolated\n", "# test_pred_fake_na['interpolated'] = interpolated\n", "# del interpolated\n", @@ -414,7 +415,7 @@ "metadata": {}, "outputs": [], "source": [ - "feat_freq_val.value_counts().sort_index().head() # require more than one feat?" + "feat_freq_val.value_counts().sort_index().head() # require more than one feat?" ] }, { @@ -429,9 +430,11 @@ "errors_val = errors_val.join(freq_feat).sort_values(by='freq', ascending=True)\n", "\n", "\n", - "errors_val_smoothed = errors_val.copy() #.loc[feat_freq_val > 1]\n", - "errors_val_smoothed[errors_val.columns[:-1]] = errors_val[errors_val.columns[:-1]].rolling(window=200, min_periods=1).mean()\n", - "ax = errors_val_smoothed.plot(x='freq', figsize=(15,10) )\n", + "errors_val_smoothed = errors_val.copy() # .loc[feat_freq_val > 1]\n", + "errors_val_smoothed[errors_val.columns[:-\n", + " 1]] = errors_val[errors_val.columns[:-\n", + " 1]].rolling(window=200, min_periods=1).mean()\n", + "ax = errors_val_smoothed.plot(x='freq', figsize=(15, 10))\n", "# errors_val_smoothed" ] }, @@ -463,8 +466,8 @@ "source": [ "## Comparisons\n", "\n", - "> Note: The interpolated values have less predictions for comparisons than the ones based on models (CF, DAE, VAE) \n", - "> The comparison is therefore not 100% fair as the interpolated samples will have more common ones (especailly the sparser the data) \n", + "> Note: The interpolated values have less predictions for comparisons than the ones based on models (CF, DAE, VAE)\n", + "> The comparison is therefore not 100% fair as the interpolated samples will have more common ones (especailly the sparser the data)\n", "> Could be changed." ] }, @@ -477,7 +480,7 @@ "\n", "- all measured (identified, observed) peptides in validation data\n", "\n", - "> Does not make too much sense to compare collab and AEs, \n", + "> Does not make too much sense to compare collab and AEs,\n", "> as the setup differs of training and validation data differs" ] }, @@ -518,7 +521,9 @@ "source": [ "### Test Datasplit\n", "\n", - "Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction." + "Fake NAs : Artificially created NAs. Some data was sampled and set\n", + "explicitly to misssing before it was fed to the model for\n", + "reconstruction." ] }, { @@ -597,7 +602,7 @@ "source": [ "# val\n", "fname = args.out_preds / f\"pred_val_{args.model_key}.csv\"\n", - "setattr(args, fname.stem, fname.as_posix()) # add [] assignment?\n", + "setattr(args, fname.stem, fname.as_posix()) # add [] assignment?\n", "val_pred_fake_na.to_csv(fname)\n", "# test\n", "fname = args.out_preds / f\"pred_test_{args.model_key}.csv\"\n", @@ -620,7 +625,7 @@ "metadata": {}, "outputs": [], "source": [ - "figures # switch to fnames?" + "figures # switch to fnames?" ] }, { @@ -630,7 +635,7 @@ "metadata": {}, "outputs": [], "source": [ - "args.dump(fname=args.out_models/ f\"model_config_{args.model_key}.yaml\")\n", + "args.dump(fname=args.out_models / f\"model_config_{args.model_key}.yaml\")\n", "args" ] } diff --git a/project/01_1_train_Median.py b/project/01_1_train_Median.py index 33d169b61..72a7cf562 100644 --- a/project/01_1_train_Median.py +++ b/project/01_1_train_Median.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -43,17 +43,17 @@ # %% tags=["parameters"] # files and folders -folder_experiment:str = 'runs/example' # Datasplit folder with data for experiment -file_format: str = 'csv' # file format of create splits, default pickle (pkl) -fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv' # Machine parsed metadata from rawfile workflow +folder_experiment: str = 'runs/example' # Datasplit folder with data for experiment +file_format: str = 'csv' # file format of create splits, default pickle (pkl) +fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv' # Metadata for samples # model -sample_idx_position: int = 0 # position of index which is sample ID -model_key: str = 'Median' # model key (lower cased version will be used for file names) -model: str = 'Median' # model name -save_pred_real_na: bool = True # Save all predictions for real na +sample_idx_position: int = 0 # position of index which is sample ID +model_key: str = 'Median' # model key (lower cased version will be used for file names) +model: str = 'Median' # model name +save_pred_real_na: bool = True # Save all predictions for real na # metadata -> defaults for metadata extracted from machine data -meta_date_col: str = None # date column in meta data -meta_cat_col: str = None # category column in meta data +meta_date_col: str = None # date column in meta data +meta_cat_col: str = None # category column in meta data # %% [markdown] @@ -79,7 +79,7 @@ # ## Load data in long format # %% -data = datasplits.DataSplits.from_folder(args.data, file_format=args.file_format) +data = datasplits.DataSplits.from_folder(args.data, file_format=args.file_format) # %% [markdown] # data is loaded in long format @@ -88,12 +88,12 @@ data.train_X.sample(5) # %% [markdown] -# Infer index names from long format +# Infer index names from long format # %% index_columns = list(data.train_X.index.names) sample_id = index_columns.pop(args.sample_idx_position) -if len(index_columns) == 1: +if len(index_columns) == 1: index_column = index_columns.pop() index_columns = None logger.info(f"{sample_id = }, single feature: {index_column = }") @@ -126,13 +126,13 @@ # %% freq_feat = vaep.io.datasplits.load_freq(args.data) -freq_feat.head() # training data +freq_feat.head() # training data # %% [markdown] # ### Produce some addional fake samples # %% [markdown] -# The validation fake NA is used to by all models to evaluate training performance. +# The validation fake NA is used to by all models to evaluate training performance. # %% val_pred_fake_na = data.val_y.to_frame(name='observed') @@ -143,7 +143,6 @@ test_pred_fake_na.describe() - # %% [markdown] # ## Data in wide format # @@ -159,7 +158,7 @@ # ### Add interpolation performance # %% -# interpolated = vaep.pandas.interpolate(wide_df = data.train_X) +# interpolated = vaep.pandas.interpolate(wide_df = data.train_X) # val_pred_fake_na['interpolated'] = interpolated # test_pred_fake_na['interpolated'] = interpolated # del interpolated @@ -207,7 +206,7 @@ # freq_feat.to_frame('overall').join(feat_freq_val).plot.scatter(x='overall', y='freq_val') # %% -feat_freq_val.value_counts().sort_index().head() # require more than one feat? +feat_freq_val.value_counts().sort_index().head() # require more than one feat? # %% errors_val = val_pred_fake_na.drop('observed', axis=1).sub(val_pred_fake_na['observed'], axis=0) @@ -215,9 +214,11 @@ errors_val = errors_val.join(freq_feat).sort_values(by='freq', ascending=True) -errors_val_smoothed = errors_val.copy() #.loc[feat_freq_val > 1] -errors_val_smoothed[errors_val.columns[:-1]] = errors_val[errors_val.columns[:-1]].rolling(window=200, min_periods=1).mean() -ax = errors_val_smoothed.plot(x='freq', figsize=(15,10) ) +errors_val_smoothed = errors_val.copy() # .loc[feat_freq_val > 1] +errors_val_smoothed[errors_val.columns[:- + 1]] = errors_val[errors_val.columns[:- + 1]].rolling(window=200, min_periods=1).mean() +ax = errors_val_smoothed.plot(x='freq', figsize=(15, 10)) # errors_val_smoothed # %% @@ -230,8 +231,8 @@ # %% [markdown] # ## Comparisons # -# > Note: The interpolated values have less predictions for comparisons than the ones based on models (CF, DAE, VAE) -# > The comparison is therefore not 100% fair as the interpolated samples will have more common ones (especailly the sparser the data) +# > Note: The interpolated values have less predictions for comparisons than the ones based on models (CF, DAE, VAE) +# > The comparison is therefore not 100% fair as the interpolated samples will have more common ones (especailly the sparser the data) # > Could be changed. # %% [markdown] @@ -239,7 +240,7 @@ # # - all measured (identified, observed) peptides in validation data # -# > Does not make too much sense to compare collab and AEs, +# > Does not make too much sense to compare collab and AEs, # > as the setup differs of training and validation data differs # %% @@ -256,7 +257,9 @@ # %% [markdown] # ### Test Datasplit # -# Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction. +# Fake NAs : Artificially created NAs. Some data was sampled and set +# explicitly to misssing before it was fed to the model for +# reconstruction. # %% added_metrics = d_metrics.add_metrics(test_pred_fake_na, 'test_fake_na') @@ -285,7 +288,7 @@ # %% # val fname = args.out_preds / f"pred_val_{args.model_key}.csv" -setattr(args, fname.stem, fname.as_posix()) # add [] assignment? +setattr(args, fname.stem, fname.as_posix()) # add [] assignment? val_pred_fake_na.to_csv(fname) # test fname = args.out_preds / f"pred_test_{args.model_key}.csv" @@ -296,8 +299,8 @@ # ## Config # %% -figures # switch to fnames? +figures # switch to fnames? # %% -args.dump(fname=args.out_models/ f"model_config_{args.model_key}.yaml") +args.dump(fname=args.out_models / f"model_config_{args.model_key}.yaml") args diff --git a/project/01_1_train_RSN.ipynb b/project/01_1_train_RSN.ipynb index cee641bd3..95b208ebf 100644 --- a/project/01_1_train_RSN.ipynb +++ b/project/01_1_train_RSN.ipynb @@ -75,8 +75,8 @@ "# model\n", "sample_idx_position: int = 0 # position of index which is sample ID\n", "# model key (lower cased version will be used for file names)\n", - "axis: int = 1 # impute per row/sample (1) or per column/feat (0). \n", - "completeness = 0.6 # fractio of non missing values for row/sample (axis=0) or column/feat (axis=1)\n", + "axis: int = 1 # impute per row/sample (1) or per column/feat (0).\n", + "completeness = 0.6 # fractio of non missing values for row/sample (axis=0) or column/feat (axis=1)\n", "model_key: str = 'RSN'\n", "model: str = 'RSN' # model name\n", "save_pred_real_na: bool = True # Save all predictions for real na\n", @@ -458,7 +458,9 @@ "source": [ "### Test Datasplit\n", "\n", - "Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction." + "Fake NAs : Artificially created NAs. Some data was sampled and set\n", + "explicitly to misssing before it was fed to the model for\n", + "reconstruction." ] }, { diff --git a/project/01_1_train_RSN.py b/project/01_1_train_RSN.py index 578b2be15..73643f02a 100644 --- a/project/01_1_train_RSN.py +++ b/project/01_1_train_RSN.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -52,8 +52,8 @@ # model sample_idx_position: int = 0 # position of index which is sample ID # model key (lower cased version will be used for file names) -axis: int = 1 # impute per row/sample (1) or per column/feat (0). -completeness = 0.6 # fractio of non missing values for row/sample (axis=0) or column/feat (axis=1) +axis: int = 1 # impute per row/sample (1) or per column/feat (0). +completeness = 0.6 # fractio of non missing values for row/sample (axis=0) or column/feat (axis=1) model_key: str = 'RSN' model: str = 'RSN' # model name save_pred_real_na: bool = True # Save all predictions for real na @@ -224,7 +224,9 @@ # %% [markdown] # ### Test Datasplit # -# Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction. +# Fake NAs : Artificially created NAs. Some data was sampled and set +# explicitly to misssing before it was fed to the model for +# reconstruction. # %% added_metrics = d_metrics.add_metrics(test_pred_fake_na, 'test_fake_na') diff --git a/project/01_1_train_VAE.ipynb b/project/01_1_train_VAE.ipynb index a100b8b74..d1346cc9c 100644 --- a/project/01_1_train_VAE.ipynb +++ b/project/01_1_train_VAE.ipynb @@ -17,6 +17,7 @@ }, "outputs": [], "source": [ + "\n", "import logging\n", "\n", "\n", @@ -27,24 +28,27 @@ "\n", "from torch.nn import Sigmoid\n", "\n", - "# overwriting Recorder callback with custom plot_loss\n", - "from vaep.models import plot_loss\n", - "from fastai import learner\n", - "learner.Recorder.plot_loss = plot_loss\n", - "\n", "import pandas as pd\n", + "\n", "import sklearn\n", - "from sklearn.impute import SimpleImputer\n", "from sklearn.preprocessing import StandardScaler\n", + "from sklearn.impute import SimpleImputer\n", "\n", "import vaep\n", - "from vaep.analyzers import analyzers\n", - "import vaep.model\n", - "import vaep.models as models\n", - "from vaep.models import ae\n", + "import vaep.nb\n", "from vaep.io import datasplits\n", + "from vaep.models import ae\n", + "import vaep.models as models\n", + "import vaep.model\n", + "from vaep.analyzers import analyzers\n", + "\n", + "\n", + "# overwriting Recorder callback with custom plot_loss\n", + "from vaep.models import plot_loss\n", + "from fastai import learner\n", + "learner.Recorder.plot_loss = plot_loss\n", + "\n", "\n", - "import vaep.nb\n", "logger = vaep.logging.setup_logger(logging.getLogger('vaep'))\n", "logger.info(\n", " \"Experiment 03 - Analysis of latent spaces and performance comparisions\")\n", @@ -502,7 +506,9 @@ "id": "2231b67e", "metadata": {}, "source": [ - "Adding a `EarlyStoppingCallback` results in an error. Potential fix in [PR3509](https://github.com/fastai/fastai/pull/3509) is not yet in current version. Try again later" + "Adding a `EarlyStoppingCallback` results in an error. Potential fix in\n", + "[PR3509](https://github.com/fastai/fastai/pull/3509) is not yet in\n", + "current version. Try again later" ] }, { @@ -882,7 +888,9 @@ "source": [ "### Test Datasplit\n", "\n", - "Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction." + "Fake NAs : Artificially created NAs. Some data was sampled and set\n", + "explicitly to misssing before it was fed to the model for\n", + "reconstruction." ] }, { diff --git a/project/01_1_train_VAE.py b/project/01_1_train_VAE.py index 4943c9d0f..6e5dac203 100644 --- a/project/01_1_train_VAE.py +++ b/project/01_1_train_VAE.py @@ -17,6 +17,7 @@ # # Variational Autoencoder # %% + import logging @@ -27,24 +28,27 @@ from torch.nn import Sigmoid -# overwriting Recorder callback with custom plot_loss -from vaep.models import plot_loss -from fastai import learner -learner.Recorder.plot_loss = plot_loss - import pandas as pd + import sklearn -from sklearn.impute import SimpleImputer from sklearn.preprocessing import StandardScaler +from sklearn.impute import SimpleImputer import vaep -from vaep.analyzers import analyzers -import vaep.model -import vaep.models as models -from vaep.models import ae +import vaep.nb from vaep.io import datasplits +from vaep.models import ae +import vaep.models as models +import vaep.model +from vaep.analyzers import analyzers + + +# overwriting Recorder callback with custom plot_loss +from vaep.models import plot_loss +from fastai import learner +learner.Recorder.plot_loss = plot_loss + -import vaep.nb logger = vaep.logging.setup_logger(logging.getLogger('vaep')) logger.info( "Experiment 03 - Analysis of latent spaces and performance comparisions") @@ -264,7 +268,9 @@ analysis.learn.show_training_loop() # %% [markdown] -# Adding a `EarlyStoppingCallback` results in an error. Potential fix in [PR3509](https://github.com/fastai/fastai/pull/3509) is not yet in current version. Try again later +# Adding a `EarlyStoppingCallback` results in an error. Potential fix in +# [PR3509](https://github.com/fastai/fastai/pull/3509) is not yet in +# current version. Try again later # %% # learn.summary() @@ -438,7 +444,9 @@ # %% [markdown] # ### Test Datasplit # -# Fake NAs : Artificially created NAs. Some data was sampled and set explicitly to misssing before it was fed to the model for reconstruction. +# Fake NAs : Artificially created NAs. Some data was sampled and set +# explicitly to misssing before it was fed to the model for +# reconstruction. # %% added_metrics = d_metrics.add_metrics(test_pred_fake_na, 'test_fake_na') diff --git a/project/01_1_transfer_NAGuideR_pred.py b/project/01_1_transfer_NAGuideR_pred.py index 3b85de686..18058df57 100644 --- a/project/01_1_transfer_NAGuideR_pred.py +++ b/project/01_1_transfer_NAGuideR_pred.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python diff --git a/project/02_1_aggregate_metrics.py.py b/project/02_1_aggregate_metrics.py.py index 3c7945550..ea11f334a 100644 --- a/project/02_1_aggregate_metrics.py.py +++ b/project/02_1_aggregate_metrics.py.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python diff --git a/project/02_1_join_metrics.py.ipynb b/project/02_1_join_metrics.py.ipynb index 387a722f6..561f06525 100644 --- a/project/02_1_join_metrics.py.ipynb +++ b/project/02_1_join_metrics.py.ipynb @@ -38,9 +38,7 @@ "cell_type": "code", "execution_count": 4, "id": "df472356", - "metadata": { - "lines_to_next_cell": 1 - }, + "metadata": {}, "outputs": [], "source": [ "filepath_out" @@ -52,7 +50,7 @@ "metadata": {}, "outputs": [], "source": [ - "## Example \n", + "## Example\n", "\n", "- first file" ] @@ -64,6 +62,8 @@ "metadata": {}, "outputs": [], "source": [ + "\n", + "\n", "def process(fpath: str) -> pd.DataFrame:\n", " df = pd.read_csv(fpath, index_col=POS_INDEX_COL, header=list(range(N_HEADER_COLS)))\n", " return df\n", diff --git a/project/02_1_join_metrics.py.py b/project/02_1_join_metrics.py.py index ec2aae537..8b395c187 100644 --- a/project/02_1_join_metrics.py.py +++ b/project/02_1_join_metrics.py.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -30,11 +30,13 @@ filepath_out # %% [markdown] -# ## Example +# ## Example # # - first file # %% + + def process(fpath: str) -> pd.DataFrame: df = pd.read_csv(fpath, index_col=POS_INDEX_COL, header=list(range(N_HEADER_COLS))) return df diff --git a/project/02_2_aggregate_configs.py.ipynb b/project/02_2_aggregate_configs.py.ipynb index 2d36b6b43..cdb9d77fb 100644 --- a/project/02_2_aggregate_configs.py.ipynb +++ b/project/02_2_aggregate_configs.py.ipynb @@ -20,10 +20,12 @@ "source": [ "from pathlib import Path\n", "import pandas as pd\n", - "pd.options.display.max_columns = 30 \n", "\n", - "from vaep.models.collect_dumps import collect_configs\n", "from vaep.logging import setup_nb_logger\n", + "from vaep.models.collect_dumps import collect_configs\n", + "\n", + "pd.options.display.max_columns = 30\n", + "\n", "logger = setup_nb_logger()" ] }, diff --git a/project/02_2_aggregate_configs.py.py b/project/02_2_aggregate_configs.py.py index f820ef03e..dc8ba3a3a 100644 --- a/project/02_2_aggregate_configs.py.py +++ b/project/02_2_aggregate_configs.py.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -20,10 +20,12 @@ # %% from pathlib import Path import pandas as pd -pd.options.display.max_columns = 30 -from vaep.models.collect_dumps import collect_configs from vaep.logging import setup_nb_logger +from vaep.models.collect_dumps import collect_configs + +pd.options.display.max_columns = 30 + logger = setup_nb_logger() # %% diff --git a/project/02_2_join_configs.py.ipynb b/project/02_2_join_configs.py.ipynb index 8b51442fb..4d1b871f5 100644 --- a/project/02_2_join_configs.py.ipynb +++ b/project/02_2_join_configs.py.ipynb @@ -103,7 +103,7 @@ ], "metadata": { "kernelspec": { - "display_name": "vaep", + "display_name": "Python 3", "language": "python", "name": "python3" }, diff --git a/project/02_2_join_configs.py.py b/project/02_2_join_configs.py.py index 36a18ccc4..d8381e119 100644 --- a/project/02_2_join_configs.py.py +++ b/project/02_2_join_configs.py.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.0 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python diff --git a/project/02_3_grid_search_analysis.ipynb b/project/02_3_grid_search_analysis.ipynb index b47d75474..440b99b21 100644 --- a/project/02_3_grid_search_analysis.ipynb +++ b/project/02_3_grid_search_analysis.ipynb @@ -21,18 +21,18 @@ "import plotly.express as px\n", "import matplotlib\n", "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", "\n", - "\n", + "import vaep.plotting.plotly as px_vaep\n", + "from vaep.analyzers import compare_predictions\n", + "from vaep import sampling\n", + "from vaep.io import datasplits\n", + "import vaep.utils\n", + "import vaep.pandas\n", + "import vaep.io\n", "import vaep.nb\n", "matplotlib.rcParams['figure.figsize'] = [12.0, 6.0]\n", "\n", - "import vaep.io\n", - "import vaep.pandas\n", - "import vaep.utils\n", - "from vaep.io import datasplits\n", - "from vaep import sampling\n", - "from vaep.analyzers import compare_predictions\n", - "import vaep.plotting.plotly as px_vaep\n", "\n", "pd.options.display.max_columns = 45\n", "pd.options.display.max_rows = 100\n", @@ -70,8 +70,8 @@ }, "outputs": [], "source": [ - "metrics_csv:str = \"path/to/all_metrics.csv\" # file path to metrics\n", - "configs_csv:str = \"path/to/all_configs.csv\" # file path to configs (\"meta data\")" + "metrics_csv: str = \"path/to/all_metrics.csv\" # file path to metrics\n", + "configs_csv: str = \"path/to/all_configs.csv\" # file path to configs (\"meta data\")" ] }, { @@ -170,7 +170,7 @@ "source": [ "# ToDo: integrate as parameters\n", "metric_columns = ['MSE', 'MAE']\n", - "model_keys = metrics.stack('model').index.levels[-1].unique().to_list() # not used\n", + "model_keys = metrics.stack('model').index.levels[-1].unique().to_list() # not used\n", "subset = metrics.columns.levels[0][0]\n", "print(f\"{subset = }\")" ] @@ -204,16 +204,16 @@ "meta['hidden_layers'] = (meta\n", " .loc[meta['hidden_layers'].notna(), 'hidden_layers']\n", " .apply(lambda x: tuple(eval(x)))\n", - ")\n", + " )\n", "meta['n_hidden_layers'] = (meta\n", " .loc[meta['hidden_layers'].notna(), 'hidden_layers']\n", " .apply(len)\n", - ")\n", + " )\n", "meta['n_hidden_layers'] = (meta\n", " ['n_hidden_layers']\n", " .fillna(0)\n", " .astype(int)\n", - ")\n", + " )\n", "meta.loc[meta['hidden_layers'].isna(), 'hidden_layers'] = None\n", "meta = meta.set_index('id')\n", "meta" @@ -225,7 +225,8 @@ "id": "b4dd468f-8995-403d-a389-6c4e4e912cd5", "metadata": {}, "source": [ - "Batch size for collab models depends on a factor (as the data in long format has roughly N samples * M features entries)." + "Batch size for collab models depends on a factor (as the data in long\n", + "format has roughly N samples * M features entries)." ] }, { @@ -271,19 +272,19 @@ "source": [ "# ToDo: To make it cleaner: own config for each model (interpolated and median)\n", "metrics_styled = (metrics\n", - " .set_index(\n", - " pd.MultiIndex\n", - " .from_frame(\n", - " meta\n", - " .loc[metrics.index, ['latent_dim', 'hidden_layers', 'batch_size']]\n", - " # .loc[metrics.index]\n", - " )\n", - " )\n", - " .sort_index()\n", - " .stack('model')\n", - " .drop_duplicates()\n", - " .style.background_gradient(cmap)\n", - ")\n", + " .set_index(\n", + " pd.MultiIndex\n", + " .from_frame(\n", + " meta\n", + " .loc[metrics.index, ['latent_dim', 'hidden_layers', 'batch_size']]\n", + " # .loc[metrics.index]\n", + " )\n", + " )\n", + " .sort_index()\n", + " .stack('model')\n", + " .drop_duplicates()\n", + " .style.background_gradient(cmap)\n", + " )\n", "\n", "metrics = metrics_styled.data\n", "metrics_styled" @@ -354,7 +355,7 @@ "metadata": {}, "outputs": [], "source": [ - "metrics_long = pd.read_csv(path_metrics, index_col=[0], header=[0,1,2])\n", + "metrics_long = pd.read_csv(path_metrics, index_col=[0], header=[0, 1, 2])\n", "# columns_names = ['subset', 'data_split', 'model', 'metric_name']\n", "columns_names = list(metrics_long.columns.names)\n", "metrics_long.sample(5) if len(metrics_long) > 15 else metrics_long" @@ -395,13 +396,13 @@ "outputs": [], "source": [ "metrics_prop = (metrics_long\n", - " .loc[:, pd.IndexSlice[:, :, 'prop']]\n", - " .stack(['data_split', 'model'])\n", - " .reset_index()\n", - " .drop_duplicates()\n", - " .set_index(['id', 'data_split', 'model'])\n", - " .astype(int)\n", - " )\n", + " .loc[:, pd.IndexSlice[:, :, 'prop']]\n", + " .stack(['data_split', 'model'])\n", + " .reset_index()\n", + " .drop_duplicates()\n", + " .set_index(['id', 'data_split', 'model'])\n", + " .astype(int)\n", + " )\n", "metrics_prop" ] }, @@ -427,7 +428,7 @@ " .to_frame('metric_value')\n", " .reset_index('metric_name')\n", " .join(metrics_N)\n", - ")\n", + " )\n", "metrics_long" ] }, @@ -450,7 +451,7 @@ "metrics_long = (metrics_long\n", " .reset_index(['data_split'])\n", " .join(meta.set_index('model', append=True))\n", - " ).reset_index('model')\n", + " ).reset_index('model')\n", "# metrics_long.index.name = 'id'\n", "metrics_long.sample(5)" ] @@ -549,7 +550,7 @@ "id": "c4607c64-2e90-4ed6-b337-8e210d7c37de", "metadata": {}, "source": [ - "# Collection of Performance plots \n", + "# Collection of Performance plots\n", "\n", "- specify `labels_dict` for plotly plotting\n", "\n" @@ -607,7 +608,6 @@ }, "outputs": [], "source": [ - "import seaborn as sns\n", "plt.rcParams['figure.figsize'] = (8, 4)\n", "plt.rcParams['lines.linewidth'] = 2\n", "plt.rcParams['lines.markersize'] = 3\n", @@ -620,9 +620,9 @@ " x='n_params',\n", " y='metric_value',\n", " col=\"data_split\",\n", - " col_order = col_order,\n", + " col_order=col_order,\n", " row=\"metric_name\",\n", - " row_order = row_order,\n", + " row_order=row_order,\n", " hue=\"model\",\n", " # style=\"day\",\n", " palette=vaep.plotting.defaults.color_model_mapping,\n", @@ -633,11 +633,11 @@ "fg.fig.get_size_inches()\n", "\n", "(ax_00, ax_01), (ax_10, ax_11) = fg.axes\n", - "ax_00.set_ylabel('MAE')\n", - "ax_10.set_ylabel('MSE')\n", - "_ = ax_00.set_title('validation data')\n", - "_ = ax_01.set_title('test data')\n", - "ax_10.set_xlabel('number of parameters')\n", + "ax_00.set_ylabel(row_order[0])\n", + "ax_10.set_ylabel(row_order[1])\n", + "_ = ax_00.set_title('validation data') # col_order[0]\n", + "_ = ax_01.set_title('test data') # col_order[1]\n", + "ax_10.set_xlabel('number of parameters') # n_params\n", "ax_11.set_xlabel('number of parameters')\n", "ax_10.xaxis.set_major_formatter(\"{x:,.0f}\")\n", "ax_11.xaxis.set_major_formatter(\"{x:,.0f}\")\n", @@ -686,6 +686,7 @@ " yaxis={'title': {'standoff': 6}})\n", " return fig\n", "\n", + "\n", "dataset = \"test_fake_na\"\n", "fig = plot_by_params(dataset)\n", "fname = FOLDER / f\"hyperpar_{dataset}_results_by_parameters.pdf\"\n", @@ -730,8 +731,8 @@ "source": [ "group_by = ['data_split', 'latent_dim', 'metric_name', 'model']\n", "metrics_long_sel_min = metrics_long.reset_index(\n", - " ).groupby(by=group_by\n", - " ).apply(lambda df: df.sort_values(by='metric_value').iloc[0])\n", + ").groupby(by=group_by\n", + " ).apply(lambda df: df.sort_values(by='metric_value').iloc[0])\n", "metrics_long_sel_min" ] }, @@ -813,7 +814,7 @@ "source": [ "dataset = 'valid_fake_na'\n", "group_by = ['data_split', 'metric_name', 'model', 'latent_dim']\n", - "METRIC = 'MAE' # params.metric\n", + "METRIC = 'MAE' # params.metric\n", "selected = (metrics_long\n", " .reset_index()\n", " .groupby(by=group_by)\n", @@ -864,11 +865,11 @@ "outputs": [], "source": [ "min_latent = (selected\n", - " .loc[METRIC]\n", - " .loc[model_with_latent]\n", - " .groupby(level='latent_dim')\n", - " .agg({'metric_value': 'mean'})\n", - " .sort_values('metric_value')\n", + " .loc[METRIC]\n", + " .loc[model_with_latent]\n", + " .groupby(level='latent_dim')\n", + " .agg({'metric_value': 'mean'})\n", + " .sort_values('metric_value')\n", " )\n", "min_latent" ] @@ -1034,10 +1035,10 @@ " .value_counts()\n", " .sort_index()\n", " .plot(style='.',\n", - " xlabel='number of samples',\n", - " ylabel='observations')\n", - ")\n", - "vaep.savefig(ax.get_figure(), files_out[f'n_obs_error_counts_{dataset}.pdf'])" + " xlabel='number of samples',\n", + " ylabel='observations')\n", + " )\n", + "vaep.savefig(ax.get_figure(), files_out[f'n_obs_error_counts_{dataset}.pdf'])" ] }, { @@ -1117,8 +1118,8 @@ "msg_annotation = f\"(Latend dim: {min_latent}, No. of feat: {M_feat}, window_size: {window_size})\"\n", "print(msg_annotation)\n", "\n", - "files_out[f'best_models_ld_{min_latent}_rolling_errors_by_freq'] = (FOLDER /\n", - " f'best_models_ld_{min_latent}_rolling_errors_by_freq')\n", + "files_out[f'best_models_ld_{min_latent}_rolling_errors_by_freq'] = (\n", + " FOLDER / f'best_models_ld_{min_latent}_rolling_errors_by_freq')\n", "vaep.savefig(\n", " ax.get_figure(),\n", " name=files_out[f'best_models_ld_{min_latent}_rolling_errors_by_freq'])" @@ -1165,8 +1166,8 @@ " )\n", "fig = px_vaep.apply_default_layout(fig)\n", "fig.update_layout(legend_title_text='') # remove legend title\n", - "files_out[f'best_models_ld_{min_latent}_errors_by_freq_plotly.html'] = (FOLDER /\n", - " f'best_models_ld_{min_latent}_errors_by_freq_plotly.html')\n", + "files_out[f'best_models_ld_{min_latent}_errors_by_freq_plotly.html'] = (\n", + " FOLDER / f'best_models_ld_{min_latent}_errors_by_freq_plotly.html')\n", "fig.write_html(\n", " files_out[f'best_models_ld_{min_latent}_errors_by_freq_plotly.html'])\n", "fig" @@ -1205,8 +1206,8 @@ " # title='mean error for features averaged for each frequency'\n", " xlim=(FREQ_MIN, freq_feat.max())\n", ")\n", - "files_out[f'best_models_ld_{min_latent}_errors_by_freq_averaged'] = (FOLDER /\n", - " f'best_models_ld_{min_latent}_errors_by_freq_averaged')\n", + "files_out[f'best_models_ld_{min_latent}_errors_by_freq_averaged'] = (\n", + " FOLDER / f'best_models_ld_{min_latent}_errors_by_freq_averaged')\n", "vaep.savefig(\n", " ax.get_figure(),\n", " files_out[f'best_models_ld_{min_latent}_errors_by_freq_averaged'])" diff --git a/project/02_3_grid_search_analysis.py b/project/02_3_grid_search_analysis.py index cd36ae19a..24c0ce374 100644 --- a/project/02_3_grid_search_analysis.py +++ b/project/02_3_grid_search_analysis.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -22,18 +22,18 @@ import plotly.express as px import matplotlib import matplotlib.pyplot as plt +import seaborn as sns - +import vaep.plotting.plotly as px_vaep +from vaep.analyzers import compare_predictions +from vaep import sampling +from vaep.io import datasplits +import vaep.utils +import vaep.pandas +import vaep.io import vaep.nb matplotlib.rcParams['figure.figsize'] = [12.0, 6.0] -import vaep.io -import vaep.pandas -import vaep.utils -from vaep.io import datasplits -from vaep import sampling -from vaep.analyzers import compare_predictions -import vaep.plotting.plotly as px_vaep pd.options.display.max_columns = 45 pd.options.display.max_rows = 100 @@ -48,8 +48,8 @@ # papermill parameters: # %% tags=["parameters"] -metrics_csv:str = "path/to/all_metrics.csv" # file path to metrics -configs_csv:str = "path/to/all_configs.csv" # file path to configs ("meta data") +metrics_csv: str = "path/to/all_metrics.csv" # file path to metrics +configs_csv: str = "path/to/all_configs.csv" # file path to configs ("meta data") # %% try: @@ -92,7 +92,7 @@ # %% # ToDo: integrate as parameters metric_columns = ['MSE', 'MAE'] -model_keys = metrics.stack('model').index.levels[-1].unique().to_list() # not used +model_keys = metrics.stack('model').index.levels[-1].unique().to_list() # not used subset = metrics.columns.levels[0][0] print(f"{subset = }") @@ -107,22 +107,23 @@ meta['hidden_layers'] = (meta .loc[meta['hidden_layers'].notna(), 'hidden_layers'] .apply(lambda x: tuple(eval(x))) -) + ) meta['n_hidden_layers'] = (meta .loc[meta['hidden_layers'].notna(), 'hidden_layers'] .apply(len) -) + ) meta['n_hidden_layers'] = (meta ['n_hidden_layers'] .fillna(0) .astype(int) -) + ) meta.loc[meta['hidden_layers'].isna(), 'hidden_layers'] = None meta = meta.set_index('id') meta # %% [markdown] -# Batch size for collab models depends on a factor (as the data in long format has roughly N samples * M features entries). +# Batch size for collab models depends on a factor (as the data in long +# format has roughly N samples * M features entries). # %% [markdown] # ## Colorcoded metrics @@ -141,19 +142,19 @@ # %% # ToDo: To make it cleaner: own config for each model (interpolated and median) metrics_styled = (metrics - .set_index( - pd.MultiIndex - .from_frame( - meta - .loc[metrics.index, ['latent_dim', 'hidden_layers', 'batch_size']] - # .loc[metrics.index] - ) - ) - .sort_index() - .stack('model') - .drop_duplicates() - .style.background_gradient(cmap) -) + .set_index( + pd.MultiIndex + .from_frame( + meta + .loc[metrics.index, ['latent_dim', 'hidden_layers', 'batch_size']] + # .loc[metrics.index] + ) + ) + .sort_index() + .stack('model') + .drop_duplicates() + .style.background_gradient(cmap) + ) metrics = metrics_styled.data metrics_styled @@ -189,7 +190,7 @@ # Rebuild metrics from dictionary # %% -metrics_long = pd.read_csv(path_metrics, index_col=[0], header=[0,1,2]) +metrics_long = pd.read_csv(path_metrics, index_col=[0], header=[0, 1, 2]) # columns_names = ['subset', 'data_split', 'model', 'metric_name'] columns_names = list(metrics_long.columns.names) metrics_long.sample(5) if len(metrics_long) > 15 else metrics_long @@ -210,13 +211,13 @@ # %% metrics_prop = (metrics_long - .loc[:, pd.IndexSlice[:, :, 'prop']] - .stack(['data_split', 'model']) - .reset_index() - .drop_duplicates() - .set_index(['id', 'data_split', 'model']) - .astype(int) - ) + .loc[:, pd.IndexSlice[:, :, 'prop']] + .stack(['data_split', 'model']) + .reset_index() + .drop_duplicates() + .set_index(['id', 'data_split', 'model']) + .astype(int) + ) metrics_prop # %% [markdown] @@ -229,7 +230,7 @@ .to_frame('metric_value') .reset_index('metric_name') .join(metrics_N) -) + ) metrics_long # %% [markdown] @@ -239,7 +240,7 @@ metrics_long = (metrics_long .reset_index(['data_split']) .join(meta.set_index('model', append=True)) - ).reset_index('model') + ).reset_index('model') # metrics_long.index.name = 'id' metrics_long.sample(5) @@ -286,7 +287,7 @@ logger.info(f"Saved metrics in long format: {fname}") # %% [markdown] -# # Collection of Performance plots +# # Collection of Performance plots # # - specify `labels_dict` for plotly plotting # @@ -316,7 +317,6 @@ hover_data['metric_value'] = ':.4f' # %% -import seaborn as sns plt.rcParams['figure.figsize'] = (8, 4) plt.rcParams['lines.linewidth'] = 2 plt.rcParams['lines.markersize'] = 3 @@ -329,9 +329,9 @@ x='n_params', y='metric_value', col="data_split", - col_order = col_order, + col_order=col_order, row="metric_name", - row_order = row_order, + row_order=row_order, hue="model", # style="day", palette=vaep.plotting.defaults.color_model_mapping, @@ -344,9 +344,9 @@ (ax_00, ax_01), (ax_10, ax_11) = fg.axes ax_00.set_ylabel(row_order[0]) ax_10.set_ylabel(row_order[1]) -_ = ax_00.set_title('validation data') # col_order[0] -_ = ax_01.set_title('test data') # col_order[1] -ax_10.set_xlabel('number of parameters') # n_params +_ = ax_00.set_title('validation data') # col_order[0] +_ = ax_01.set_title('test data') # col_order[1] +ax_10.set_xlabel('number of parameters') # n_params ax_11.set_xlabel('number of parameters') ax_10.xaxis.set_major_formatter("{x:,.0f}") ax_11.xaxis.set_major_formatter("{x:,.0f}") @@ -388,6 +388,7 @@ def plot_by_params(data_split: str = '', subset: str = ''): yaxis={'title': {'standoff': 6}}) return fig + dataset = "test_fake_na" fig = plot_by_params(dataset) fname = FOLDER / f"hyperpar_{dataset}_results_by_parameters.pdf" @@ -412,8 +413,8 @@ def plot_by_params(data_split: str = '', subset: str = ''): # %% group_by = ['data_split', 'latent_dim', 'metric_name', 'model'] metrics_long_sel_min = metrics_long.reset_index( - ).groupby(by=group_by - ).apply(lambda df: df.sort_values(by='metric_value').iloc[0]) +).groupby(by=group_by + ).apply(lambda df: df.sort_values(by='metric_value').iloc[0]) metrics_long_sel_min @@ -469,7 +470,7 @@ def get_plotly_figure(dataset: str, x='latent_dim'): # %% dataset = 'valid_fake_na' group_by = ['data_split', 'metric_name', 'model', 'latent_dim'] -METRIC = 'MAE' # params.metric +METRIC = 'MAE' # params.metric selected = (metrics_long .reset_index() .groupby(by=group_by) @@ -494,11 +495,11 @@ def get_plotly_figure(dataset: str, x='latent_dim'): # %% min_latent = (selected - .loc[METRIC] - .loc[model_with_latent] - .groupby(level='latent_dim') - .agg({'metric_value': 'mean'}) - .sort_values('metric_value') + .loc[METRIC] + .loc[model_with_latent] + .groupby(level='latent_dim') + .agg({'metric_value': 'mean'}) + .sort_values('metric_value') ) min_latent @@ -581,10 +582,10 @@ def get_plotly_figure(dataset: str, x='latent_dim'): .value_counts() .sort_index() .plot(style='.', - xlabel='number of samples', - ylabel='observations') -) -vaep.savefig(ax.get_figure(), files_out[f'n_obs_error_counts_{dataset}.pdf']) + xlabel='number of samples', + ylabel='observations') + ) +vaep.savefig(ax.get_figure(), files_out[f'n_obs_error_counts_{dataset}.pdf']) # %% ax = errors.plot.scatter('freq', 'n_obs') @@ -621,8 +622,8 @@ def get_plotly_figure(dataset: str, x='latent_dim'): msg_annotation = f"(Latend dim: {min_latent}, No. of feat: {M_feat}, window_size: {window_size})" print(msg_annotation) -files_out[f'best_models_ld_{min_latent}_rolling_errors_by_freq'] = (FOLDER / - f'best_models_ld_{min_latent}_rolling_errors_by_freq') +files_out[f'best_models_ld_{min_latent}_rolling_errors_by_freq'] = ( + FOLDER / f'best_models_ld_{min_latent}_rolling_errors_by_freq') vaep.savefig( ax.get_figure(), name=files_out[f'best_models_ld_{min_latent}_rolling_errors_by_freq']) @@ -647,8 +648,8 @@ def get_plotly_figure(dataset: str, x='latent_dim'): ) fig = px_vaep.apply_default_layout(fig) fig.update_layout(legend_title_text='') # remove legend title -files_out[f'best_models_ld_{min_latent}_errors_by_freq_plotly.html'] = (FOLDER / - f'best_models_ld_{min_latent}_errors_by_freq_plotly.html') +files_out[f'best_models_ld_{min_latent}_errors_by_freq_plotly.html'] = ( + FOLDER / f'best_models_ld_{min_latent}_errors_by_freq_plotly.html') fig.write_html( files_out[f'best_models_ld_{min_latent}_errors_by_freq_plotly.html']) fig @@ -673,8 +674,8 @@ def get_plotly_figure(dataset: str, x='latent_dim'): # title='mean error for features averaged for each frequency' xlim=(FREQ_MIN, freq_feat.max()) ) -files_out[f'best_models_ld_{min_latent}_errors_by_freq_averaged'] = (FOLDER / - f'best_models_ld_{min_latent}_errors_by_freq_averaged') +files_out[f'best_models_ld_{min_latent}_errors_by_freq_averaged'] = ( + FOLDER / f'best_models_ld_{min_latent}_errors_by_freq_averaged') vaep.savefig( ax.get_figure(), files_out[f'best_models_ld_{min_latent}_errors_by_freq_averaged']) diff --git a/project/02_4_best_models_over_all_data.ipynb b/project/02_4_best_models_over_all_data.ipynb index 17c3f0dde..f252973d2 100644 --- a/project/02_4_best_models_over_all_data.ipynb +++ b/project/02_4_best_models_over_all_data.ipynb @@ -78,7 +78,7 @@ "source": [ "# snakemake.params.folder\n", "try:\n", - " models = snakemake.params.models # snakefile would need to be\n", + " models = snakemake.params.models # snakefile would need to be\n", "except AttributeError:\n", " models = ['Median', 'interpolated', 'CF', 'DAE', 'VAE']\n", "models" @@ -155,9 +155,9 @@ "outputs": [], "source": [ "_unique = metrics_long[\"data level\"].unique()\n", - "order_categories['data level'] = [l for l in order_categories['data level'] if l in _unique] #ensure predefined order\n", + "order_categories['data level'] = [l for l in order_categories['data level'] if l in _unique] # ensure predefined order\n", "_unique = metrics_long['model'].unique()\n", - "order_categories['model'] = [m for m in order_categories['model'] if m in _unique] #ensure predefined order\n", + "order_categories['model'] = [m for m in order_categories['model'] if m in _unique] # ensure predefined order\n", "\n", "semi_supervised = [m for m in ['CF', 'DAE', 'VAE'] if m in _unique]\n", "reference = [m for m in ['median', 'interpolated'] if m in _unique]\n", @@ -216,11 +216,11 @@ "source": [ "# select best model of top N with least parameters\n", "sel_on_val = (sel_on_val\n", - " .groupby(by=group_by)\n", - " .apply(\n", - " lambda df: df.sort_values(by='n_params').iloc[0]\n", - " )\n", - " ).loc[\n", + " .groupby(by=group_by)\n", + " .apply(\n", + " lambda df: df.sort_values(by='n_params').iloc[0]\n", + " )\n", + " ).loc[\n", " pd.IndexSlice[dataset, IDX_ORDER[0], 'MAE', IDX_ORDER[1]],\n", " selected_cols]\n", "sel_on_val.to_excel(writer, sheet_name=f'selected')\n", @@ -248,13 +248,13 @@ "idx = sel_on_val.droplevel(level='data_split').index\n", "sel_on_val = sel_on_val.reset_index(['latent_dim', 'hidden_layers', 'id'])\n", "\n", - "test_results = ( metrics_long\n", - " .query('data_split == \"test_fake_na\"')\n", - " .reset_index().set_index(idx.names)\n", - " .loc[idx]\n", - " .reset_index(['latent_dim', 'hidden_layers', 'id'])\n", - " .set_index('data_split', append=True)\n", - ")[selected_cols]\n", + "test_results = (metrics_long\n", + " .query('data_split == \"test_fake_na\"')\n", + " .reset_index().set_index(idx.names)\n", + " .loc[idx]\n", + " .reset_index(['latent_dim', 'hidden_layers', 'id'])\n", + " .set_index('data_split', append=True)\n", + " )[selected_cols]\n", "test_results" ] }, @@ -329,7 +329,7 @@ "metadata": {}, "outputs": [], "source": [ - "### Validation data results " + "### Validation data results" ] }, { @@ -344,7 +344,7 @@ "_to_plot = sel_on_val.reset_index(level=['data level', 'model']).loc[[('valid_fake_na', METRIC), ]]\n", "\n", "_to_plot = _to_plot.set_index(['data level', 'model'])[['metric_value', 'text']]\n", - "_to_plot = _to_plot.loc[IDX_ORDER,:]\n", + "_to_plot = _to_plot.loc[IDX_ORDER, :]\n", "_to_plot.index.name = ''\n", "# text = test_results['text'].unstack().loc[IDX_ORDER].unstack()\n", "_to_plot = _to_plot['metric_value'].unstack().loc[IDX_ORDER]\n", @@ -383,7 +383,8 @@ "fname = 'best_models_1_val_plotly'\n", "_to_plot = sel_on_val.reset_index(level=['data level', 'model']).loc[[('valid_fake_na', METRIC), ]]\n", "_to_plot = _to_plot.set_index(['data level', 'model'])\n", - "_to_plot[['metric_value', 'latent_dim', 'hidden_layers', 'text']] = _to_plot[['metric_value', 'latent_dim', 'hidden_layers', 'text']].fillna('-')\n", + "_to_plot[['metric_value', 'latent_dim', 'hidden_layers', 'text']] = _to_plot[[\n", + " 'metric_value', 'latent_dim', 'hidden_layers', 'text']].fillna('-')\n", "\n", "_to_plot = _to_plot.loc[pd.IndexSlice[IDX_ORDER], :]\n", "_to_plot.to_csv(FOLDER / f\"{fname}.csv\")\n", @@ -401,7 +402,7 @@ "fig = px.bar(_to_plot.reset_index(),\n", " x='data level',\n", " y='metric_value',\n", - " hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data\n", + " hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data\n", " color='model',\n", " barmode=\"group\",\n", " text='text',\n", @@ -439,8 +440,8 @@ " f' & metric_name == \"{METRIC}\"')\n", "\n", "best_on_average = metrics_long_sel.reset_index(\n", - " ).groupby(by=group_by\n", - " )['metric_value'].mean().sort_values().reset_index(level=group_by[1:])\n", + ").groupby(by=group_by\n", + " )['metric_value'].mean().sort_values().reset_index(level=group_by[1:])\n", "best_on_average" ] }, @@ -477,21 +478,21 @@ "data_split = 'test_fake_na'\n", "\n", "metrics_long_sel_test = metrics_long.query(f'data_split == \"{data_split}\"'\n", - " f' & metric_name == \"{METRIC}\"')\n", + " f' & metric_name == \"{METRIC}\"')\n", "\n", "to_plot = (metrics_long_sel_test\n", - " .reset_index().set_index(group_by)\n", - " .loc[best_on_average.index]\n", - " .reset_index().set_index(['model', 'data level'])\n", - " .loc[pd.IndexSlice[order_categories['model'], order_categories['data level']], :])\n", + " .reset_index().set_index(group_by)\n", + " .loc[best_on_average.index]\n", + " .reset_index().set_index(['model', 'data level'])\n", + " .loc[pd.IndexSlice[order_categories['model'], order_categories['data level']], :])\n", "\n", "\n", "to_plot = to_plot.reset_index()\n", "to_plot['model annotated'] = to_plot['model'] + ' - ' + to_plot['text']\n", - "order_model = to_plot['model annotated'].drop_duplicates().to_list() # model name with annotation\n", + "order_model = to_plot['model annotated'].drop_duplicates().to_list() # model name with annotation\n", "\n", "to_plot = to_plot.drop_duplicates(subset=['model', 'data level', 'metric_value'])\n", - "to_plot.to_csv(FOLDER /f\"{fname}.csv\")\n", + "to_plot.to_csv(FOLDER / f\"{fname}.csv\")\n", "to_plot" ] }, @@ -502,7 +503,7 @@ "metadata": {}, "outputs": [], "source": [ - "figsize= (10,8) # None # (10,8)\n", + "figsize = (10, 8) # None # (10,8)\n", "fig, ax = plt.subplots(figsize=figsize)\n", "to_plot.columns.name = ''\n", "ax = (to_plot\n", @@ -517,7 +518,19 @@ " width=.8,\n", " ax=ax,\n", " # colormap=\"Paired\",\n", - " color = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f','#ff7f00','#cab2d6','#6a3d9a','#ffff99','#b15928']\n", + " color=[\n", + " '#a6cee3',\n", + " '#1f78b4',\n", + " '#b2df8a',\n", + " '#33a02c',\n", + " '#fb9a99',\n", + " '#e31a1c',\n", + " '#fdbf6f',\n", + " '#ff7f00',\n", + " '#cab2d6',\n", + " '#6a3d9a',\n", + " '#ffff99',\n", + " '#b15928']\n", " )\n", " )\n", "ax = vaep.plotting.add_height_to_barplot(ax, size=11)\n", @@ -546,7 +559,7 @@ " x='model',\n", " y='metric_value',\n", " color='data level',\n", - " hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data\n", + " hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data\n", " barmode=\"group\",\n", " color_discrete_sequence=px.colors.colorbrewer.Paired,\n", " # color_discrete_sequence=['#a6cee3', '#1f78b4', '#b2df8a'],\n", @@ -583,14 +596,14 @@ " .loc[best_on_average.index].reset_index()\n", " .set_index(['model', 'data level'])\n", " .loc[pd.IndexSlice[order_categories['model'], order_categories['data level']], :]\n", - " )\n", + " )\n", "\n", "to_plot = to_plot.reset_index()\n", "to_plot['model annotated'] = to_plot['model'] + ' - ' + to_plot['text']\n", - "order_model = to_plot['model annotated'].drop_duplicates().to_list() # model name with annotation\n", + "order_model = to_plot['model annotated'].drop_duplicates().to_list() # model name with annotation\n", "\n", "to_plot = to_plot.drop_duplicates(subset=['model', 'data level', 'metric_value'])\n", - "to_plot.to_csv(FOLDER /f\"{fname}.csv\")\n", + "to_plot.to_csv(FOLDER / f\"{fname}.csv\")\n", "to_plot" ] }, @@ -601,7 +614,7 @@ "metadata": {}, "outputs": [], "source": [ - "figsize= (10,8) # None # (10,8)\n", + "figsize = (10, 8) # None # (10,8)\n", "fig, ax = plt.subplots(figsize=figsize)\n", "to_plot.columns.name = ''\n", "ax = (to_plot\n", @@ -616,7 +629,19 @@ " width=.8,\n", " ax=ax,\n", " # colormap=\"Paired\",\n", - " color = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f','#ff7f00','#cab2d6','#6a3d9a','#ffff99','#b15928']\n", + " color=[\n", + " '#a6cee3',\n", + " '#1f78b4',\n", + " '#b2df8a',\n", + " '#33a02c',\n", + " '#fb9a99',\n", + " '#e31a1c',\n", + " '#fdbf6f',\n", + " '#ff7f00',\n", + " '#cab2d6',\n", + " '#6a3d9a',\n", + " '#ffff99',\n", + " '#b15928']\n", " )\n", " )\n", "ax = vaep.plotting.add_height_to_barplot(ax, size=11)\n", @@ -645,7 +670,7 @@ " x='model',\n", " y='metric_value',\n", " color='data level',\n", - " hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data\n", + " hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data\n", " barmode=\"group\",\n", " color_discrete_sequence=px.colors.colorbrewer.Paired,\n", " # color_discrete_sequence=['#a6cee3', '#1f78b4', '#b2df8a'],\n", diff --git a/project/02_4_best_models_over_all_data.py b/project/02_4_best_models_over_all_data.py index ffb4b941f..3aea8ecae 100644 --- a/project/02_4_best_models_over_all_data.py +++ b/project/02_4_best_models_over_all_data.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -59,7 +59,7 @@ # %% # snakemake.params.folder try: - models = snakemake.params.models # snakefile would need to be + models = snakemake.params.models # snakefile would need to be except AttributeError: models = ['Median', 'interpolated', 'CF', 'DAE', 'VAE'] models @@ -96,9 +96,9 @@ # %% _unique = metrics_long["data level"].unique() -order_categories['data level'] = [l for l in order_categories['data level'] if l in _unique] #ensure predefined order +order_categories['data level'] = [l for l in order_categories['data level'] if l in _unique] # ensure predefined order _unique = metrics_long['model'].unique() -order_categories['model'] = [m for m in order_categories['model'] if m in _unique] #ensure predefined order +order_categories['model'] = [m for m in order_categories['model'] if m in _unique] # ensure predefined order semi_supervised = [m for m in ['CF', 'DAE', 'VAE'] if m in _unique] reference = [m for m in ['median', 'interpolated'] if m in _unique] @@ -137,11 +137,11 @@ # %% # select best model of top N with least parameters sel_on_val = (sel_on_val - .groupby(by=group_by) - .apply( - lambda df: df.sort_values(by='n_params').iloc[0] - ) - ).loc[ + .groupby(by=group_by) + .apply( + lambda df: df.sort_values(by='n_params').iloc[0] + ) + ).loc[ pd.IndexSlice[dataset, IDX_ORDER[0], 'MAE', IDX_ORDER[1]], selected_cols] sel_on_val.to_excel(writer, sheet_name=f'selected') @@ -156,13 +156,13 @@ idx = sel_on_val.droplevel(level='data_split').index sel_on_val = sel_on_val.reset_index(['latent_dim', 'hidden_layers', 'id']) -test_results = ( metrics_long - .query('data_split == "test_fake_na"') - .reset_index().set_index(idx.names) - .loc[idx] - .reset_index(['latent_dim', 'hidden_layers', 'id']) - .set_index('data_split', append=True) -)[selected_cols] +test_results = (metrics_long + .query('data_split == "test_fake_na"') + .reset_index().set_index(idx.names) + .loc[idx] + .reset_index(['latent_dim', 'hidden_layers', 'id']) + .set_index('data_split', append=True) + )[selected_cols] test_results # %% [markdown] @@ -197,7 +197,7 @@ vaep.savefig(fig, fname, folder=FOLDER) # %% [markdown] -# ### Validation data results +# ### Validation data results # %% fname = 'best_models_1_val_mpl' @@ -205,7 +205,7 @@ _to_plot = sel_on_val.reset_index(level=['data level', 'model']).loc[[('valid_fake_na', METRIC), ]] _to_plot = _to_plot.set_index(['data level', 'model'])[['metric_value', 'text']] -_to_plot = _to_plot.loc[IDX_ORDER,:] +_to_plot = _to_plot.loc[IDX_ORDER, :] _to_plot.index.name = '' # text = test_results['text'].unstack().loc[IDX_ORDER].unstack() _to_plot = _to_plot['metric_value'].unstack().loc[IDX_ORDER] @@ -230,7 +230,8 @@ fname = 'best_models_1_val_plotly' _to_plot = sel_on_val.reset_index(level=['data level', 'model']).loc[[('valid_fake_na', METRIC), ]] _to_plot = _to_plot.set_index(['data level', 'model']) -_to_plot[['metric_value', 'latent_dim', 'hidden_layers', 'text']] = _to_plot[['metric_value', 'latent_dim', 'hidden_layers', 'text']].fillna('-') +_to_plot[['metric_value', 'latent_dim', 'hidden_layers', 'text']] = _to_plot[[ + 'metric_value', 'latent_dim', 'hidden_layers', 'text']].fillna('-') _to_plot = _to_plot.loc[pd.IndexSlice[IDX_ORDER], :] _to_plot.to_csv(FOLDER / f"{fname}.csv") @@ -241,7 +242,7 @@ fig = px.bar(_to_plot.reset_index(), x='data level', y='metric_value', - hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data + hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data color='model', barmode="group", text='text', @@ -266,8 +267,8 @@ f' & metric_name == "{METRIC}"') best_on_average = metrics_long_sel.reset_index( - ).groupby(by=group_by - )['metric_value'].mean().sort_values().reset_index(level=group_by[1:]) +).groupby(by=group_by + )['metric_value'].mean().sort_values().reset_index(level=group_by[1:]) best_on_average # %% @@ -284,25 +285,25 @@ data_split = 'test_fake_na' metrics_long_sel_test = metrics_long.query(f'data_split == "{data_split}"' - f' & metric_name == "{METRIC}"') + f' & metric_name == "{METRIC}"') to_plot = (metrics_long_sel_test - .reset_index().set_index(group_by) - .loc[best_on_average.index] - .reset_index().set_index(['model', 'data level']) - .loc[pd.IndexSlice[order_categories['model'], order_categories['data level']], :]) + .reset_index().set_index(group_by) + .loc[best_on_average.index] + .reset_index().set_index(['model', 'data level']) + .loc[pd.IndexSlice[order_categories['model'], order_categories['data level']], :]) to_plot = to_plot.reset_index() to_plot['model annotated'] = to_plot['model'] + ' - ' + to_plot['text'] -order_model = to_plot['model annotated'].drop_duplicates().to_list() # model name with annotation +order_model = to_plot['model annotated'].drop_duplicates().to_list() # model name with annotation to_plot = to_plot.drop_duplicates(subset=['model', 'data level', 'metric_value']) -to_plot.to_csv(FOLDER /f"{fname}.csv") +to_plot.to_csv(FOLDER / f"{fname}.csv") to_plot # %% -figsize= (10,8) # None # (10,8) +figsize = (10, 8) # None # (10,8) fig, ax = plt.subplots(figsize=figsize) to_plot.columns.name = '' ax = (to_plot @@ -317,7 +318,19 @@ width=.8, ax=ax, # colormap="Paired", - color = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f','#ff7f00','#cab2d6','#6a3d9a','#ffff99','#b15928'] + color=[ + '#a6cee3', + '#1f78b4', + '#b2df8a', + '#33a02c', + '#fb9a99', + '#e31a1c', + '#fdbf6f', + '#ff7f00', + '#cab2d6', + '#6a3d9a', + '#ffff99', + '#b15928'] ) ) ax = vaep.plotting.add_height_to_barplot(ax, size=11) @@ -333,7 +346,7 @@ x='model', y='metric_value', color='data level', - hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data + hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data barmode="group", color_discrete_sequence=px.colors.colorbrewer.Paired, # color_discrete_sequence=['#a6cee3', '#1f78b4', '#b2df8a'], @@ -357,18 +370,18 @@ .loc[best_on_average.index].reset_index() .set_index(['model', 'data level']) .loc[pd.IndexSlice[order_categories['model'], order_categories['data level']], :] - ) + ) to_plot = to_plot.reset_index() to_plot['model annotated'] = to_plot['model'] + ' - ' + to_plot['text'] -order_model = to_plot['model annotated'].drop_duplicates().to_list() # model name with annotation +order_model = to_plot['model annotated'].drop_duplicates().to_list() # model name with annotation to_plot = to_plot.drop_duplicates(subset=['model', 'data level', 'metric_value']) -to_plot.to_csv(FOLDER /f"{fname}.csv") +to_plot.to_csv(FOLDER / f"{fname}.csv") to_plot # %% -figsize= (10,8) # None # (10,8) +figsize = (10, 8) # None # (10,8) fig, ax = plt.subplots(figsize=figsize) to_plot.columns.name = '' ax = (to_plot @@ -383,7 +396,19 @@ width=.8, ax=ax, # colormap="Paired", - color = ['#a6cee3','#1f78b4','#b2df8a','#33a02c','#fb9a99','#e31a1c','#fdbf6f','#ff7f00','#cab2d6','#6a3d9a','#ffff99','#b15928'] + color=[ + '#a6cee3', + '#1f78b4', + '#b2df8a', + '#33a02c', + '#fb9a99', + '#e31a1c', + '#fdbf6f', + '#ff7f00', + '#cab2d6', + '#6a3d9a', + '#ffff99', + '#b15928'] ) ) ax = vaep.plotting.add_height_to_barplot(ax, size=11) @@ -399,7 +424,7 @@ x='model', y='metric_value', color='data level', - hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data + hover_data={'N': ':,d', 'n_params': ':,d'}, # format hover data barmode="group", color_discrete_sequence=px.colors.colorbrewer.Paired, # color_discrete_sequence=['#a6cee3', '#1f78b4', '#b2df8a'], diff --git a/project/03_1_best_models_comparison.ipynb b/project/03_1_best_models_comparison.ipynb index aff217903..0a02134a1 100644 --- a/project/03_1_best_models_comparison.ipynb +++ b/project/03_1_best_models_comparison.ipynb @@ -150,8 +150,8 @@ " split,\n", " :, 'MAE']].stack(1)\n", "view_long = (selected.stack()\n", - " .to_frame('MAE')\n", - " .reset_index())\n", + " .to_frame('MAE')\n", + " .reset_index())\n", "view_long" ] }, diff --git a/project/03_1_best_models_comparison.py b/project/03_1_best_models_comparison.py index 7061b53e2..00bcb8ada 100644 --- a/project/03_1_best_models_comparison.py +++ b/project/03_1_best_models_comparison.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -94,8 +94,8 @@ split, :, 'MAE']].stack(1) view_long = (selected.stack() - .to_frame('MAE') - .reset_index()) + .to_frame('MAE') + .reset_index()) view_long # %% diff --git a/project/03_2_best_models_comparison_fig2.py b/project/03_2_best_models_comparison_fig2.py index 1af9ae1a7..f5e66baca 100644 --- a/project/03_2_best_models_comparison_fig2.py +++ b/project/03_2_best_models_comparison_fig2.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python diff --git a/project/03_3_combine_experiment_result_tables.ipynb b/project/03_3_combine_experiment_result_tables.ipynb index a0b3a2d69..476023e23 100644 --- a/project/03_3_combine_experiment_result_tables.ipynb +++ b/project/03_3_combine_experiment_result_tables.ipynb @@ -34,7 +34,7 @@ "metadata": {}, "outputs": [], "source": [ - "files = {Path(f).parent.name: f for f in snakemake.input }\n", + "files = {Path(f).parent.name: f for f in snakemake.input}\n", "files" ] }, @@ -47,7 +47,7 @@ "source": [ "table = []\n", "for key, file in files.items():\n", - " df = pd.read_excel(file, sheet_name='cp_mean_perf', index_col=0)\n", + " df = pd.read_excel(file, sheet_name=-1, index_col=0)\n", " df.columns = pd.MultiIndex.from_tuples([(key, x) for x in df.columns])\n", " table.append(df)\n", "\n", @@ -71,10 +71,10 @@ "outputs": [], "source": [ "order = (table\n", - " .loc[:, pd.IndexSlice[:, 'val']]\n", - " .mean(axis=1)\n", - " .sort_values()\n", - ")\n", + " .loc[:, pd.IndexSlice[:, 'val']]\n", + " .mean(axis=1)\n", + " .sort_values()\n", + " )\n", "order" ] }, diff --git a/project/03_3_combine_experiment_result_tables.py b/project/03_3_combine_experiment_result_tables.py index 7ba8472ba..37dd49f26 100644 --- a/project/03_3_combine_experiment_result_tables.py +++ b/project/03_3_combine_experiment_result_tables.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -23,7 +23,7 @@ # Use parent folder name as key # %% -files = {Path(f).parent.name: f for f in snakemake.input } +files = {Path(f).parent.name: f for f in snakemake.input} files # %% @@ -41,10 +41,10 @@ # %% order = (table - .loc[:, pd.IndexSlice[:, 'val']] - .mean(axis=1) - .sort_values() -) + .loc[:, pd.IndexSlice[:, 'val']] + .mean(axis=1) + .sort_values() + ) order # %% diff --git a/project/03_4_join_tables.py b/project/03_4_join_tables.py index 88e1004f1..f27f29253 100644 --- a/project/03_4_join_tables.py +++ b/project/03_4_join_tables.py @@ -7,7 +7,7 @@ # %% fname = 'runs/appl_ald_data/plasma/proteinGroups_all/01_2_performance_summary.xlsx' ald_pg_perf = pd.read_excel(fname, sheet_name=-1, index_col=0) -ald_pg_perf.columns = pd.MultiIndex.from_tuples([('ALD data','protein groups', x) for x in ald_pg_perf.columns]) +ald_pg_perf.columns = pd.MultiIndex.from_tuples([('ALD data', 'protein groups', x) for x in ald_pg_perf.columns]) ald_pg_perf # %% @@ -29,10 +29,10 @@ # %% order = (table - .loc[:, pd.IndexSlice[:, :, 'val']] - .mean(axis=1) - .sort_values() -) + .loc[:, pd.IndexSlice[:, :, 'val']] + .mean(axis=1) + .sort_values() + ) order # %% @@ -63,10 +63,10 @@ # %% # %% order = (table - .loc[:, pd.IndexSlice[:, 'val']] - .mean(axis=1) - .sort_values() -) + .loc[:, pd.IndexSlice[:, 'val']] + .mean(axis=1) + .sort_values() + ) order # %% diff --git a/project/03_5_join_benchmarks.py b/project/03_5_join_benchmarks.py index 976e3e339..493dff1b1 100644 --- a/project/03_5_join_benchmarks.py +++ b/project/03_5_join_benchmarks.py @@ -17,6 +17,8 @@ # %% # find folders in root folder and get files with tsv extension + + def find_tsv_benchmarks(root_folder: Path): """Find snakemake benchmark files in subfolders of root_folder (pimms workflow) @@ -39,6 +41,7 @@ def find_tsv_benchmarks(root_folder: Path): if file.suffix == '.tsv': yield file + files = find_tsv_benchmarks(root_folder) # %% @@ -47,7 +50,7 @@ def find_tsv_benchmarks(root_folder: Path): # files = (x for x in files if x.is_file()) # %% -COL = 'h:m:s' # 's' for seconds +COL = 'h:m:s' # 's' for seconds SPLIT_TERM = '_train_' data = dict() for file in files: @@ -64,7 +67,7 @@ def find_tsv_benchmarks(root_folder: Path): data = (pd .DataFrame(data) .drop('PRED') -) + ) data # %% diff --git a/project/04_1_train_pimms_models.ipynb b/project/04_1_train_pimms_models.ipynb index 21ac7cd0f..5f305f5d6 100644 --- a/project/04_1_train_pimms_models.ipynb +++ b/project/04_1_train_pimms_models.ipynb @@ -188,7 +188,7 @@ "id": "a76ba4ce", "metadata": {}, "source": [ - "Let's set up collaborative filtering without a validation or test set, using \n", + "Let's set up collaborative filtering without a validation or test set, using\n", "all the data there is." ] }, @@ -257,10 +257,10 @@ "metadata": {}, "outputs": [], "source": [ - "df_imputed = df_imputed.stack() # long-format\n", + "df_imputed = df_imputed.stack() # long-format\n", "observed = df_imputed.loc[df.index]\n", "imputed = df_imputed.loc[df_imputed.index.difference(df.index)]\n", - "df_imputed = df_imputed.unstack() # back to wide-format\n", + "df_imputed = df_imputed.unstack() # back to wide-format\n", "# some checks\n", "assert len(df) == len(observed)\n", "assert df_imputed.shape[0] * df_imputed.shape[1] == len(imputed) + len(observed)" @@ -273,30 +273,30 @@ "metadata": {}, "outputs": [], "source": [ - "fig, axes = plt.subplots(2, figsize=(8,4))\n", + "fig, axes = plt.subplots(2, figsize=(8, 4))\n", "\n", "min_max = vaep.plotting.data.get_min_max_iterable(\n", " [observed, imputed])\n", "label_template = '{method} (N={n:,d})'\n", "ax, _ = vaep.plotting.data.plot_histogram_intensities(\n", - " observed,\n", - " ax=axes[0],\n", - " min_max=min_max,\n", - " label=label_template.format(method='measured',\n", - " n=len(observed),\n", - " ),\n", - " color='grey',\n", - " alpha=1)\n", + " observed,\n", + " ax=axes[0],\n", + " min_max=min_max,\n", + " label=label_template.format(method='measured',\n", + " n=len(observed),\n", + " ),\n", + " color='grey',\n", + " alpha=1)\n", "_ = ax.legend()\n", "ax, _ = vaep.plotting.data.plot_histogram_intensities(\n", - " imputed,\n", - " ax=axes[1],\n", - " min_max=min_max,\n", - " label=label_template.format(method='CF imputed',\n", - " n=len(imputed),\n", - " ),\n", - " color=color_model_mapping['CF'],\n", - " alpha=1)\n", + " imputed,\n", + " ax=axes[1],\n", + " min_max=min_max,\n", + " label=label_template.format(method='CF imputed',\n", + " n=len(imputed),\n", + " ),\n", + " color=color_model_mapping['CF'],\n", + " alpha=1)\n", "_ = ax.legend()" ] }, @@ -330,8 +330,8 @@ "metadata": {}, "source": [ "The AutoEncoder model currently need validation data for training.\n", - "We will use 10% of the training data for validation. \n", - "> Expect this limitation to be dropped in the next release. It will still be recommended \n", + "We will use 10% of the training data for validation.\n", + "> Expect this limitation to be dropped in the next release. It will still be recommended\n", "> to use validation data for early stopping." ] }, @@ -352,7 +352,7 @@ "metadata": {}, "source": [ "We will use the `sampling` module to sample the validation data from the training data.\n", - "Could be split differently by providing another `weights` vector. " + "Could be split differently by providing another `weights` vector." ] }, { @@ -423,7 +423,7 @@ "metadata": {}, "outputs": [], "source": [ - "model_selected = 'VAE' # 'DAE'\n", + "model_selected = 'VAE' # 'DAE'\n", "model = AETransformer(\n", " model=model_selected,\n", " hidden_layers=[512,],\n", @@ -535,8 +535,8 @@ "metadata": {}, "outputs": [], "source": [ - "df = df.stack() # long-format\n", - "df_imputed = df_imputed.stack() # long-format\n", + "df = df.stack() # long-format\n", + "df_imputed = df_imputed.stack() # long-format\n", "observed = df_imputed.loc[df.index]\n", "imputed = df_imputed.loc[df_imputed.index.difference(df.index)]" ] @@ -550,30 +550,30 @@ }, "outputs": [], "source": [ - "fig, axes = plt.subplots(2, figsize=(8,4))\n", + "fig, axes = plt.subplots(2, figsize=(8, 4))\n", "\n", "min_max = vaep.plotting.data.get_min_max_iterable(\n", " [observed, imputed])\n", "label_template = '{method} (N={n:,d})'\n", "ax, _ = vaep.plotting.data.plot_histogram_intensities(\n", - " observed,\n", - " ax=axes[0],\n", - " min_max=min_max,\n", - " label=label_template.format(method='measured',\n", - " n=len(observed),\n", - " ),\n", - " color='grey',\n", - " alpha=1)\n", + " observed,\n", + " ax=axes[0],\n", + " min_max=min_max,\n", + " label=label_template.format(method='measured',\n", + " n=len(observed),\n", + " ),\n", + " color='grey',\n", + " alpha=1)\n", "_ = ax.legend()\n", "ax, _ = vaep.plotting.data.plot_histogram_intensities(\n", - " imputed,\n", - " ax=axes[1],\n", - " min_max=min_max,\n", - " label=label_template.format(method=f'{model_selected} imputed',\n", - " n=len(imputed),\n", - " ),\n", - " color=color_model_mapping[model_selected],\n", - " alpha=1)\n", + " imputed,\n", + " ax=axes[1],\n", + " min_max=min_max,\n", + " label=label_template.format(method=f'{model_selected} imputed',\n", + " n=len(imputed),\n", + " ),\n", + " color=color_model_mapping[model_selected],\n", + " alpha=1)\n", "_ = ax.legend()" ] }, diff --git a/project/04_1_train_pimms_models.py b/project/04_1_train_pimms_models.py index fea106857..3ddae8b24 100644 --- a/project/04_1_train_pimms_models.py +++ b/project/04_1_train_pimms_models.py @@ -86,7 +86,7 @@ # # # # CollaborativeFilteringTransformer? # %% [markdown] -# Let's set up collaborative filtering without a validation or test set, using +# Let's set up collaborative filtering without a validation or test set, using # all the data there is. # %% @@ -117,39 +117,39 @@ # Let's plot the distribution of the imputed values vs the ones used for training: # %% -df_imputed = df_imputed.stack() # long-format +df_imputed = df_imputed.stack() # long-format observed = df_imputed.loc[df.index] imputed = df_imputed.loc[df_imputed.index.difference(df.index)] -df_imputed = df_imputed.unstack() # back to wide-format +df_imputed = df_imputed.unstack() # back to wide-format # some checks assert len(df) == len(observed) assert df_imputed.shape[0] * df_imputed.shape[1] == len(imputed) + len(observed) # %% -fig, axes = plt.subplots(2, figsize=(8,4)) +fig, axes = plt.subplots(2, figsize=(8, 4)) min_max = vaep.plotting.data.get_min_max_iterable( [observed, imputed]) label_template = '{method} (N={n:,d})' ax, _ = vaep.plotting.data.plot_histogram_intensities( - observed, - ax=axes[0], - min_max=min_max, - label=label_template.format(method='measured', - n=len(observed), - ), - color='grey', - alpha=1) + observed, + ax=axes[0], + min_max=min_max, + label=label_template.format(method='measured', + n=len(observed), + ), + color='grey', + alpha=1) _ = ax.legend() ax, _ = vaep.plotting.data.plot_histogram_intensities( - imputed, - ax=axes[1], - min_max=min_max, - label=label_template.format(method='CF imputed', - n=len(imputed), - ), - color=color_model_mapping['CF'], - alpha=1) + imputed, + ax=axes[1], + min_max=min_max, + label=label_template.format(method='CF imputed', + n=len(imputed), + ), + color=color_model_mapping['CF'], + alpha=1) _ = ax.legend() # %% [markdown] @@ -166,8 +166,8 @@ # %% [markdown] # The AutoEncoder model currently need validation data for training. -# We will use 10% of the training data for validation. -# > Expect this limitation to be dropped in the next release. It will still be recommended +# We will use 10% of the training data for validation. +# > Expect this limitation to be dropped in the next release. It will still be recommended # > to use validation data for early stopping. # %% @@ -176,7 +176,7 @@ # %% [markdown] # We will use the `sampling` module to sample the validation data from the training data. -# Could be split differently by providing another `weights` vector. +# Could be split differently by providing another `weights` vector. # %% val_X, train_X = vaep.sampling.sample_data(df.stack(), @@ -204,7 +204,7 @@ # Select either `DAE` or `VAE` model: # %% -model_selected = 'VAE' # 'DAE' +model_selected = 'VAE' # 'DAE' model = AETransformer( model=model_selected, hidden_layers=[512,], @@ -257,36 +257,36 @@ df_imputed = df_imputed.replace(val_X) # %% -df = df.stack() # long-format -df_imputed = df_imputed.stack() # long-format +df = df.stack() # long-format +df_imputed = df_imputed.stack() # long-format observed = df_imputed.loc[df.index] imputed = df_imputed.loc[df_imputed.index.difference(df.index)] # %% -fig, axes = plt.subplots(2, figsize=(8,4)) +fig, axes = plt.subplots(2, figsize=(8, 4)) min_max = vaep.plotting.data.get_min_max_iterable( [observed, imputed]) label_template = '{method} (N={n:,d})' ax, _ = vaep.plotting.data.plot_histogram_intensities( - observed, - ax=axes[0], - min_max=min_max, - label=label_template.format(method='measured', - n=len(observed), - ), - color='grey', - alpha=1) + observed, + ax=axes[0], + min_max=min_max, + label=label_template.format(method='measured', + n=len(observed), + ), + color='grey', + alpha=1) _ = ax.legend() ax, _ = vaep.plotting.data.plot_histogram_intensities( - imputed, - ax=axes[1], - min_max=min_max, - label=label_template.format(method=f'{model_selected} imputed', - n=len(imputed), - ), - color=color_model_mapping[model_selected], - alpha=1) + imputed, + ax=axes[1], + min_max=min_max, + label=label_template.format(method=f'{model_selected} imputed', + n=len(imputed), + ), + color=color_model_mapping[model_selected], + alpha=1) _ = ax.legend() diff --git a/project/10_0_ald_data.ipynb b/project/10_0_ald_data.ipynb index 01027e035..e006f94e4 100644 --- a/project/10_0_ald_data.ipynb +++ b/project/10_0_ald_data.ipynb @@ -47,14 +47,14 @@ "print(*(folder_data.iterdir()), sep='\\n')\n", "\n", "fnames = dict(\n", - "plasma_proteinGroups = folder_data / 'Protein_ALDupgrade_Report.csv',\n", - "plasma_aggPeptides = folder_data / 'ald_proteome_spectronaut.tsv',\n", - "liver_proteinGroups = folder_data / 'Protein_20200221_121354_20200218_ALD_LiverTissue_PlateS1_Atlaslib_Report.csv',\n", - "liver_aggPeptides = folder_data / 'Peptide_20220819_100847_20200218_ALD_LiverTissue_PlateS1_Atlaslib_Report.csv',\n", - "annotations = folder_data / 'ald_experiment_annotations.csv',\n", - "clinic = folder_data / 'labtest_integrated_numeric.csv',\n", - "raw_meta = folder_data / 'ald_metadata_rawfiles.csv')\n", - "fnames =vaep.nb.Config.from_dict(fnames) # could be handeled kwargs as in normal dict" + " plasma_proteinGroups=folder_data / 'Protein_ALDupgrade_Report.csv',\n", + " plasma_aggPeptides=folder_data / 'ald_proteome_spectronaut.tsv',\n", + " liver_proteinGroups=folder_data / 'Protein_20200221_121354_20200218_ALD_LiverTissue_PlateS1_Atlaslib_Report.csv',\n", + " liver_aggPeptides=folder_data / 'Peptide_20220819_100847_20200218_ALD_LiverTissue_PlateS1_Atlaslib_Report.csv',\n", + " annotations=folder_data / 'ald_experiment_annotations.csv',\n", + " clinic=folder_data / 'labtest_integrated_numeric.csv',\n", + " raw_meta=folder_data / 'ald_metadata_rawfiles.csv')\n", + "fnames = vaep.nb.Config.from_dict(fnames) # could be handeled kwargs as in normal dict" ] }, { @@ -128,7 +128,7 @@ "metadata": {}, "outputs": [], "source": [ - "annotations['Participant ID'].value_counts().value_counts() # some only have a blood sample, some both" + "annotations['Participant ID'].value_counts().value_counts() # some only have a blood sample, some both" ] }, { @@ -306,7 +306,7 @@ "metadata": {}, "outputs": [], "source": [ - "clinic.loc[idx_overlap_plasma].to_csv(folder_data_out /'ald_metadata_cli.csv')" + "clinic.loc[idx_overlap_plasma].to_csv(folder_data_out / 'ald_metadata_cli.csv')" ] }, { @@ -456,7 +456,7 @@ "id": "cfe1c458-dc61-4890-b430-6efa7eb89e72", "metadata": {}, "source": [ - "## (Aggregated) Peptide Data " + "## (Aggregated) Peptide Data" ] }, { @@ -603,7 +603,7 @@ "metadata": {}, "outputs": [], "source": [ - "id_mappings = [\"PEP.StrippedSequence\", \"PG.ProteinAccessions\", \"PG.Genes\"]\n", + "id_mappings = [\"PEP.StrippedSequence\", \"PG.ProteinAccessions\", \"PG.Genes\"]\n", "id_mappings = meta[id_mappings].drop_duplicates()\n", "id_mappings.to_csv(folder_data_out / 'ald_plasma_aggPeptides_id_mappings.csv')\n", "id_mappings" @@ -618,25 +618,26 @@ "\n", "taken from [Spectronaut manuel](https://biognosys.com/resources/spectronaut-manual/)\n", "\n", - "feature | description \n", + "feature | description\n", "--- | ---\n", "PEP.IsProteinGroupSpecific | True or False. Tells you whether the peptide only belongs to one Protein Group.\n", "PEP.StrippedSequence | -\n", "PEP.IsProteotypic | -\n", "PEP.PeptidePosition | -\n", - "PG.Cscore | - \n", + "PG.Cscore | -\n", "PG.ProteinAccessions | -\n", - "PG.Genes | - \n", + "PG.Genes | -\n", "PEP.Quantity | The quantitative value for that peptide as defined in the settings.\n", - "EG.PrecursorId | Unique Id for the precursor: [modified sequence] plus [charge] \n", + "EG.PrecursorId | Unique Id for the precursor: [modified sequence] plus [charge]\n", "EG.Qvalue | The q-value (FDR) of the EG.\n", - "EG.TotalQuantity (Settings) | The quantitative value for that EG as defined in the settings. \n", + "EG.TotalQuantity (Settings) | The quantitative value for that EG as defined in the settings.\n", "\n", - "> Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. \n", + "> Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious.\n", "\n", - "> Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. \n", + "> Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious.\n", "\n", - "After discussing with Lili, `PEP.Quantity` is the fitting entity for each unique aggregated Peptide. Duplicated entries are just to drop" + "After discussing with Lili, `PEP.Quantity` is the fitting entity for\n", + "each unique aggregated Peptide. Duplicated entries are just to drop" ] }, { @@ -646,7 +647,7 @@ "metadata": {}, "outputs": [], "source": [ - "sel_cols = ['Sample ID', 'PEP.StrippedSequence', 'PEP.Quantity'] # selected quantity in last position\n", + "sel_cols = ['Sample ID', 'PEP.StrippedSequence', 'PEP.Quantity'] # selected quantity in last position\n", "df = df.reset_index()[sel_cols].drop_duplicates().set_index(sel_cols[:2])\n", "df" ] @@ -691,7 +692,7 @@ "id": "b823acaf-2610-4b0a-91d8-2d6dd6ff4182", "metadata": {}, "source": [ - "- rawfile metadata -> keep " + "- rawfile metadata -> keep" ] }, { @@ -732,7 +733,8 @@ "id": "5dddafbb-edd7-4ef0-9787-3120b24d7f79", "metadata": {}, "source": [ - "For one raw file no metadata could be extracted (`ERROR: Unable to access the RAW file using the native Thermo library.`)" + "For one raw file no metadata could be extracted (`ERROR: Unable to\n", + "access the RAW file using the native Thermo library.`)" ] }, { @@ -875,7 +877,7 @@ "metadata": {}, "outputs": [], "source": [ - "id_mappings = [\"PG.ProteinAccessions\", \"PG.Genes\"]\n", + "id_mappings = [\"PG.ProteinAccessions\", \"PG.Genes\"]\n", "id_mappings = meta[id_mappings].drop_duplicates()\n", "id_mappings.to_csv(folder_data_out / 'ald_plasma_proteinGroups_id_mappings.csv', index=False)\n", "id_mappings" @@ -900,7 +902,7 @@ "outputs": [], "source": [ "column_types = ['.'.join(x for x in tup) for tup in list(column_types.unique())]\n", - "column_types # 'PG.Quantity' expected" + "column_types # 'PG.Quantity' expected" ] }, { @@ -929,11 +931,12 @@ "metadata": {}, "outputs": [], "source": [ - "def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list):\n", - " to_drop = [x for x in df.index.names if not x in idx_to_keep]\n", + "def find_idx_to_drop(df: pd.DataFrame, idx_to_keep: list):\n", + " to_drop = [x for x in df.index.names if x not in idx_to_keep]\n", " logger.info(\"Columnns to drop: {}\".format(\",\".join((str(x) for x in to_drop))))\n", " return to_drop\n", - " \n", + "\n", + "\n", "to_drop = find_idx_to_drop(df, idx_cols)\n", "df = df.reset_index(level=to_drop, drop=True)\n", "df.head()" @@ -1135,7 +1138,7 @@ " 'title': 'protein group measurement distribution'}\n", "\n", "ax = vaep.plotting.plot_counts(des_data.T.sort_values(by='count', ascending=False).reset_index(\n", - "), feat_col_name='count', n_samples=len(df), ax=None, min_feat_prop=.0,**kwargs)\n", + "), feat_col_name='count', n_samples=len(df), ax=None, min_feat_prop=.0, **kwargs)\n", "\n", "fig = ax.get_figure()\n", "fig.tight_layout()\n", @@ -1447,7 +1450,7 @@ }, "outputs": [], "source": [ - "id_mappings = [\"PEP.StrippedSequence\", \"PG.ProteinAccessions\", \"PG.Genes\"]\n", + "id_mappings = [\"PEP.StrippedSequence\", \"PG.ProteinAccessions\", \"PG.Genes\"]\n", "id_mappings = meta[id_mappings].drop_duplicates()\n", "id_mappings.to_csv(folder_data_out / 'ald_liver_aggPeptides_id_mappings.csv')\n", "id_mappings" @@ -1462,25 +1465,26 @@ "\n", "taken from [Spectronaut manuel](https://biognosys.com/resources/spectronaut-manual/)\n", "\n", - "feature | description \n", + "feature | description\n", "--- | ---\n", "PEP.IsProteinGroupSpecific | True or False. Tells you whether the peptide only belongs to one Protein Group.\n", "PEP.StrippedSequence | -\n", "PEP.IsProteotypic | -\n", "PEP.PeptidePosition | -\n", - "PG.Cscore | - \n", + "PG.Cscore | -\n", "PG.ProteinAccessions | -\n", - "PG.Genes | - \n", + "PG.Genes | -\n", "PEP.Quantity | The quantitative value for that peptide as defined in the settings.\n", - "EG.PrecursorId | Unique Id for the precursor: [modified sequence] plus [charge] \n", + "EG.PrecursorId | Unique Id for the precursor: [modified sequence] plus [charge]\n", "EG.Qvalue | The q-value (FDR) of the EG.\n", - "EG.TotalQuantity (Settings) | The quantitative value for that EG as defined in the settings. \n", + "EG.TotalQuantity (Settings) | The quantitative value for that EG as defined in the settings.\n", "\n", - "> Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. \n", + "> Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious.\n", "\n", - "> Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. \n", + "> Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious.\n", "\n", - "After discussing with Lili, `PEP.Quantity` is the fitting entity for each unique aggregated Peptide. Duplicated entries are just to drop" + "After discussing with Lili, `PEP.Quantity` is the fitting entity for\n", + "each unique aggregated Peptide. Duplicated entries are just to drop" ] }, { @@ -1490,7 +1494,7 @@ "metadata": {}, "outputs": [], "source": [ - "sel_cols = ['Sample ID', 'PEP.StrippedSequence', VAR_PEP] # selected quantity in last position\n", + "sel_cols = ['Sample ID', 'PEP.StrippedSequence', VAR_PEP] # selected quantity in last position\n", "df = df.reset_index()[sel_cols].drop_duplicates().set_index(sel_cols[:2]).squeeze()\n", "df" ] @@ -1513,7 +1517,7 @@ "metadata": {}, "source": [ "Select entry with maximum intensity of `duplicated entries`\n", - " \n", + "\n", "> change of variable and many duplicates -> could be PSM table? (close to evidence?)" ] }, @@ -1535,7 +1539,9 @@ "metadata": {}, "outputs": [], "source": [ - "df = vaep.pandas.select_max_by(df=df.reset_index(), grouping_columns=sel_cols[:-1], selection_column=sel_cols[-1]).set_index(sel_cols[:-1])" + "df = vaep.pandas.select_max_by(df=df.reset_index(),\n", + " grouping_columns=sel_cols[:-1],\n", + " selection_column=sel_cols[-1]).set_index(sel_cols[:-1])" ] }, { @@ -1545,7 +1551,7 @@ "metadata": {}, "outputs": [], "source": [ - "assert df.index.duplicated(False).sum() == 0 , \"Still missing values\"" + "assert df.index.duplicated(False).sum() == 0, \"Still missing values\"" ] }, { @@ -1577,7 +1583,7 @@ "id": "529fa0e7-7ad4-4c72-91b1-d37587835ce5", "metadata": {}, "source": [ - "- rawfile metadata -> keep " + "- rawfile metadata -> keep" ] }, { @@ -1614,7 +1620,7 @@ "%%time\n", "# des_data = df.describe() unnecessary computation which take too long\n", "des_data = df.isna().sum().to_frame('count').T\n", - "des_data " + "des_data" ] }, { @@ -1630,7 +1636,8 @@ "id": "44616770-fcc2-4a97-86f4-e0eadc98bb7a", "metadata": {}, "source": [ - "For one raw file no metadata could be extracted (`ERROR: Unable to access the RAW file using the native Thermo library.`)" + "For one raw file no metadata could be extracted (`ERROR: Unable to\n", + "access the RAW file using the native Thermo library.`)" ] }, { @@ -1777,7 +1784,7 @@ "metadata": {}, "outputs": [], "source": [ - "id_mappings = [\"PG.ProteinAccessions\", \"PG.Genes\"]\n", + "id_mappings = [\"PG.ProteinAccessions\", \"PG.Genes\"]\n", "id_mappings = meta[id_mappings].drop_duplicates()\n", "id_mappings.to_csv(folder_data_out / 'ald_liver_proteinGroups_id_mappings.csv')\n", "id_mappings" @@ -1802,7 +1809,7 @@ "outputs": [], "source": [ "column_types = ['.'.join(x for x in tup) for tup in list(column_types.unique())]\n", - "column_types # 'PG.Quantity' expected" + "column_types # 'PG.Quantity' expected" ] }, { @@ -1900,7 +1907,7 @@ "metadata": {}, "outputs": [], "source": [ - "sel_cols = ['PG.ProteinAccessions', 'PG.Genes', 'Sample ID', VAR_PG] # last one gives quantity\n", + "sel_cols = ['PG.ProteinAccessions', 'PG.Genes', 'Sample ID', VAR_PG] # last one gives quantity\n", "df = df.reset_index()[sel_cols].drop_duplicates().set_index(sel_cols[:-1])" ] }, diff --git a/project/10_0_ald_data.py b/project/10_0_ald_data.py index f0c54f0d7..1e179b55e 100644 --- a/project/10_0_ald_data.py +++ b/project/10_0_ald_data.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -38,14 +38,14 @@ print(*(folder_data.iterdir()), sep='\n') fnames = dict( -plasma_proteinGroups = folder_data / 'Protein_ALDupgrade_Report.csv', -plasma_aggPeptides = folder_data / 'ald_proteome_spectronaut.tsv', -liver_proteinGroups = folder_data / 'Protein_20200221_121354_20200218_ALD_LiverTissue_PlateS1_Atlaslib_Report.csv', -liver_aggPeptides = folder_data / 'Peptide_20220819_100847_20200218_ALD_LiverTissue_PlateS1_Atlaslib_Report.csv', -annotations = folder_data / 'ald_experiment_annotations.csv', -clinic = folder_data / 'labtest_integrated_numeric.csv', -raw_meta = folder_data / 'ald_metadata_rawfiles.csv') -fnames =vaep.nb.Config.from_dict(fnames) # could be handeled kwargs as in normal dict + plasma_proteinGroups=folder_data / 'Protein_ALDupgrade_Report.csv', + plasma_aggPeptides=folder_data / 'ald_proteome_spectronaut.tsv', + liver_proteinGroups=folder_data / 'Protein_20200221_121354_20200218_ALD_LiverTissue_PlateS1_Atlaslib_Report.csv', + liver_aggPeptides=folder_data / 'Peptide_20220819_100847_20200218_ALD_LiverTissue_PlateS1_Atlaslib_Report.csv', + annotations=folder_data / 'ald_experiment_annotations.csv', + clinic=folder_data / 'labtest_integrated_numeric.csv', + raw_meta=folder_data / 'ald_metadata_rawfiles.csv') +fnames = vaep.nb.Config.from_dict(fnames) # could be handeled kwargs as in normal dict # %% @@ -77,7 +77,7 @@ annotations # %% -annotations['Participant ID'].value_counts().value_counts() # some only have a blood sample, some both +annotations['Participant ID'].value_counts().value_counts() # some only have a blood sample, some both # %% [markdown] # ### Select ALD subcohort @@ -147,7 +147,7 @@ clinic["kleiner"].value_counts() # %% -clinic.loc[idx_overlap_plasma].to_csv(folder_data_out /'ald_metadata_cli.csv') +clinic.loc[idx_overlap_plasma].to_csv(folder_data_out / 'ald_metadata_cli.csv') # %% [markdown] # ## Rawfile information @@ -212,7 +212,7 @@ # > see section below # %% [markdown] -# ## (Aggregated) Peptide Data +# ## (Aggregated) Peptide Data # %% df = pd.read_table(fnames.plasma_aggPeptides, low_memory=False) @@ -263,7 +263,7 @@ meta.describe(include='all') # %% -id_mappings = ["PEP.StrippedSequence", "PG.ProteinAccessions", "PG.Genes"] +id_mappings = ["PEP.StrippedSequence", "PG.ProteinAccessions", "PG.Genes"] id_mappings = meta[id_mappings].drop_duplicates() id_mappings.to_csv(folder_data_out / 'ald_plasma_aggPeptides_id_mappings.csv') id_mappings @@ -273,28 +273,29 @@ # # taken from [Spectronaut manuel](https://biognosys.com/resources/spectronaut-manual/) # -# feature | description +# feature | description # --- | --- # PEP.IsProteinGroupSpecific | True or False. Tells you whether the peptide only belongs to one Protein Group. # PEP.StrippedSequence | - # PEP.IsProteotypic | - # PEP.PeptidePosition | - -# PG.Cscore | - +# PG.Cscore | - # PG.ProteinAccessions | - -# PG.Genes | - +# PG.Genes | - # PEP.Quantity | The quantitative value for that peptide as defined in the settings. -# EG.PrecursorId | Unique Id for the precursor: [modified sequence] plus [charge] +# EG.PrecursorId | Unique Id for the precursor: [modified sequence] plus [charge] # EG.Qvalue | The q-value (FDR) of the EG. -# EG.TotalQuantity (Settings) | The quantitative value for that EG as defined in the settings. +# EG.TotalQuantity (Settings) | The quantitative value for that EG as defined in the settings. # -# > Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. +# > Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. # -# > Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. +# > Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. # -# After discussing with Lili, `PEP.Quantity` is the fitting entity for each unique aggregated Peptide. Duplicated entries are just to drop +# After discussing with Lili, `PEP.Quantity` is the fitting entity for +# each unique aggregated Peptide. Duplicated entries are just to drop # %% -sel_cols = ['Sample ID', 'PEP.StrippedSequence', 'PEP.Quantity'] # selected quantity in last position +sel_cols = ['Sample ID', 'PEP.StrippedSequence', 'PEP.Quantity'] # selected quantity in last position df = df.reset_index()[sel_cols].drop_duplicates().set_index(sel_cols[:2]) df @@ -313,7 +314,7 @@ idx.describe() # %% [markdown] -# - rawfile metadata -> keep +# - rawfile metadata -> keep # %% df = df.set_index(idx) @@ -330,7 +331,8 @@ # ### Check for metadata from rawfile overlap # %% [markdown] -# For one raw file no metadata could be extracted (`ERROR: Unable to access the RAW file using the native Thermo library.`) +# For one raw file no metadata could be extracted (`ERROR: Unable to +# access the RAW file using the native Thermo library.`) # %% idx_diff = df.index.difference(raw_meta.index) @@ -390,7 +392,7 @@ meta.describe(include='all') # %% -id_mappings = ["PG.ProteinAccessions", "PG.Genes"] +id_mappings = ["PG.ProteinAccessions", "PG.Genes"] id_mappings = meta[id_mappings].drop_duplicates() id_mappings.to_csv(folder_data_out / 'ald_plasma_proteinGroups_id_mappings.csv', index=False) id_mappings @@ -401,7 +403,7 @@ # %% column_types = ['.'.join(x for x in tup) for tup in list(column_types.unique())] -column_types # 'PG.Quantity' expected +column_types # 'PG.Quantity' expected # %% df = df.set_index(list(df.columns[:N_FRIST_META])).sort_index(axis=1) @@ -412,11 +414,12 @@ # Drop index columns which are not selected # %% -def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list): - to_drop = [x for x in df.index.names if not x in idx_to_keep] +def find_idx_to_drop(df: pd.DataFrame, idx_to_keep: list): + to_drop = [x for x in df.index.names if x not in idx_to_keep] logger.info("Columnns to drop: {}".format(",".join((str(x) for x in to_drop)))) return to_drop - + + to_drop = find_idx_to_drop(df, idx_cols) df = df.reset_index(level=to_drop, drop=True) df.head() @@ -503,7 +506,7 @@ def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list): 'title': 'protein group measurement distribution'} ax = vaep.plotting.plot_counts(des_data.T.sort_values(by='count', ascending=False).reset_index( -), feat_col_name='count', n_samples=len(df), ax=None, min_feat_prop=.0,**kwargs) +), feat_col_name='count', n_samples=len(df), ax=None, min_feat_prop=.0, **kwargs) fig = ax.get_figure() fig.tight_layout() @@ -623,7 +626,7 @@ def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list): meta # %% -id_mappings = ["PEP.StrippedSequence", "PG.ProteinAccessions", "PG.Genes"] +id_mappings = ["PEP.StrippedSequence", "PG.ProteinAccessions", "PG.Genes"] id_mappings = meta[id_mappings].drop_duplicates() id_mappings.to_csv(folder_data_out / 'ald_liver_aggPeptides_id_mappings.csv') id_mappings @@ -634,28 +637,29 @@ def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list): # # taken from [Spectronaut manuel](https://biognosys.com/resources/spectronaut-manual/) # -# feature | description +# feature | description # --- | --- # PEP.IsProteinGroupSpecific | True or False. Tells you whether the peptide only belongs to one Protein Group. # PEP.StrippedSequence | - # PEP.IsProteotypic | - # PEP.PeptidePosition | - -# PG.Cscore | - +# PG.Cscore | - # PG.ProteinAccessions | - -# PG.Genes | - +# PG.Genes | - # PEP.Quantity | The quantitative value for that peptide as defined in the settings. -# EG.PrecursorId | Unique Id for the precursor: [modified sequence] plus [charge] +# EG.PrecursorId | Unique Id for the precursor: [modified sequence] plus [charge] # EG.Qvalue | The q-value (FDR) of the EG. -# EG.TotalQuantity (Settings) | The quantitative value for that EG as defined in the settings. +# EG.TotalQuantity (Settings) | The quantitative value for that EG as defined in the settings. # -# > Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. +# > Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. # -# > Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. +# > Headers related to Peptides (PEP) as defined in the settings. Many headers related to Peptides are self-explanatory. Here are the most relevant and some which are not too obvious. # -# After discussing with Lili, `PEP.Quantity` is the fitting entity for each unique aggregated Peptide. Duplicated entries are just to drop +# After discussing with Lili, `PEP.Quantity` is the fitting entity for +# each unique aggregated Peptide. Duplicated entries are just to drop # %% -sel_cols = ['Sample ID', 'PEP.StrippedSequence', VAR_PEP] # selected quantity in last position +sel_cols = ['Sample ID', 'PEP.StrippedSequence', VAR_PEP] # selected quantity in last position df = df.reset_index()[sel_cols].drop_duplicates().set_index(sel_cols[:2]).squeeze() df @@ -666,7 +670,7 @@ def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list): # %% [markdown] # Select entry with maximum intensity of `duplicated entries` -# +# # > change of variable and many duplicates -> could be PSM table? (close to evidence?) # %% @@ -674,10 +678,12 @@ def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list): df.loc[mask_idx_duplicated].sort_index() # %% -df = vaep.pandas.select_max_by(df=df.reset_index(), grouping_columns=sel_cols[:-1], selection_column=sel_cols[-1]).set_index(sel_cols[:-1]) +df = vaep.pandas.select_max_by(df=df.reset_index(), + grouping_columns=sel_cols[:-1], + selection_column=sel_cols[-1]).set_index(sel_cols[:-1]) # %% -assert df.index.duplicated(False).sum() == 0 , "Still missing values" +assert df.index.duplicated(False).sum() == 0, "Still missing values" # %% df = df.unstack() @@ -690,7 +696,7 @@ def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list): idx.describe() # %% [markdown] -# - rawfile metadata -> keep +# - rawfile metadata -> keep # %% df = df.set_index(idx) @@ -706,13 +712,14 @@ def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list): # %%time # des_data = df.describe() unnecessary computation which take too long des_data = df.isna().sum().to_frame('count').T -des_data +des_data # %% [markdown] # ### Check for metadata from rawfile overlap # %% [markdown] -# For one raw file no metadata could be extracted (`ERROR: Unable to access the RAW file using the native Thermo library.`) +# For one raw file no metadata could be extracted (`ERROR: Unable to +# access the RAW file using the native Thermo library.`) # %% # idx_diff = df.index.difference(raw_meta.index) @@ -773,7 +780,7 @@ def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list): meta.describe(include='all') # %% -id_mappings = ["PG.ProteinAccessions", "PG.Genes"] +id_mappings = ["PG.ProteinAccessions", "PG.Genes"] id_mappings = meta[id_mappings].drop_duplicates() id_mappings.to_csv(folder_data_out / 'ald_liver_proteinGroups_id_mappings.csv') id_mappings @@ -784,7 +791,7 @@ def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list): # %% column_types = ['.'.join(x for x in tup) for tup in list(column_types.unique())] -column_types # 'PG.Quantity' expected +column_types # 'PG.Quantity' expected # %% df = df.set_index(list(df.columns[:N_FRIST_META])).sort_index(axis=1) @@ -824,7 +831,7 @@ def find_idx_to_drop(df:pd.DataFrame, idx_to_keep:list): df # %% -sel_cols = ['PG.ProteinAccessions', 'PG.Genes', 'Sample ID', VAR_PG] # last one gives quantity +sel_cols = ['PG.ProteinAccessions', 'PG.Genes', 'Sample ID', VAR_PG] # last one gives quantity df = df.reset_index()[sel_cols].drop_duplicates().set_index(sel_cols[:-1]) # %% diff --git a/project/10_0_ald_data_3v3.py b/project/10_0_ald_data_3v3.py new file mode 100644 index 000000000..3d75c14c4 --- /dev/null +++ b/project/10_0_ald_data_3v3.py @@ -0,0 +1,31 @@ +# %% +from pathlib import Path +import pandas as pd + +# %% +FN_INTENSITIES = "data/ALD_study/processed/ald_plasma_proteinGroups.pkl" +fn_clinical_data = "data/ALD_study/processed/ald_metadata_cli.csv" + +FN_INTENSITIES = Path(FN_INTENSITIES) + +# %% +df = pd.read_pickle(FN_INTENSITIES) +df + +# %% +meta = pd.read_csv(fn_clinical_data, index_col=0) +meta + +# %% +sel = pd.concat( + [df.loc[meta['kleiner'] == 0].sample(3), + df.loc[meta['kleiner'] == 4].sample(3), + ]) +sel + +# %% +fname = FN_INTENSITIES.parent / f'{FN_INTENSITIES.stem}_3v3.pkl' +sel.to_pickle(fname) +fname.as_posix() + +# %% diff --git a/project/10_1_ald_diff_analysis.ipynb b/project/10_1_ald_diff_analysis.ipynb index 59b6d06ae..95ca6552e 100644 --- a/project/10_1_ald_diff_analysis.ipynb +++ b/project/10_1_ald_diff_analysis.ipynb @@ -8,7 +8,7 @@ "\n", "- load missing values predictions\n", "- leave all other values as they were\n", - "- compare missing values predicition by model with baseline method \n", + "- compare missing values predicition by model with baseline method\n", " (default: draw from shifted normal distribution. short RSN)" ] }, @@ -66,19 +66,19 @@ "folder_experiment = \"runs/appl_ald_data/plasma/proteinGroups\"\n", "folder_data: str = '' # specify data directory if needed\n", "fn_clinical_data = \"data/ALD_study/processed/ald_metadata_cli.csv\"\n", - "fn_qc_samples = '' #'data/ALD_study/processed/qc_plasma_proteinGroups.pkl'\n", + "fn_qc_samples = '' # 'data/ALD_study/processed/qc_plasma_proteinGroups.pkl'\n", "f_annotations = 'data/ALD_study/processed/ald_plasma_proteinGroups_id_mappings.csv'\n", "\n", "\n", "target: str = 'kleiner'\n", - "covar:str = 'age,bmi,gender_num,nas_steatosis_ordinal,abstinent_num'\n", + "covar: str = 'age,bmi,gender_num,nas_steatosis_ordinal,abstinent_num'\n", "\n", "file_format = \"csv\"\n", - "model_key = 'VAE' # model(s) to evaluate\n", - "model = None # default same as model_key, but could be overwritten (edge case)\n", - "value_name='intensity'\n", - "out_folder='diff_analysis'\n", - "template_pred = 'pred_real_na_{}.csv' # fixed, do not change" + "model_key = 'VAE' # model(s) to evaluate\n", + "model = None # default same as model_key, but could be overwritten (edge case)\n", + "value_name = 'intensity'\n", + "out_folder = 'diff_analysis'\n", + "template_pred = 'pred_real_na_{}.csv' # fixed, do not change" ] }, { @@ -180,7 +180,7 @@ "source": [ "df_clinic = pd.read_csv(args.fn_clinical_data, index_col=0)\n", "df_clinic = df_clinic.loc[observed.index.levels[0]]\n", - "cols_clinic = vaep.pandas.get_columns_accessor(df_clinic) # pick Berlin as reference?\n", + "cols_clinic = vaep.pandas.get_columns_accessor(df_clinic)\n", "df_clinic[[args.target, *args.covar]].describe()" ] }, @@ -321,7 +321,7 @@ "DATA_COMPLETENESS = 0.6\n", "# MIN_N_PROTEIN_GROUPS: int = 200\n", "FRAC_PROTEIN_GROUPS: int = 0.622\n", - "CV_QC_SAMPLE: float = 0.4 # Coef. of variation on 13 QC samples\n", + "CV_QC_SAMPLE: float = 0.4 # Coef. of variation on 13 QC samples\n", "\n", "ald_study, cutoffs = vaep.analyzers.diff_analysis.select_raw_data(observed.unstack(\n", "), data_completeness=DATA_COMPLETENESS, frac_protein_groups=FRAC_PROTEIN_GROUPS)\n", @@ -340,14 +340,14 @@ " qc_samples = pd.read_pickle(args.fn_qc_samples)\n", " qc_cv_feat = qc_samples.std() / qc_samples.mean()\n", " qc_cv_feat = qc_cv_feat.rename(qc_samples.columns.name)\n", - " fig, ax = plt.subplots(figsize=(4,7))\n", + " fig, ax = plt.subplots(figsize=(4, 7))\n", " ax = qc_cv_feat.plot.box(ax=ax)\n", " ax.set_ylabel('Coefficient of Variation')\n", " vaep.savefig(fig, name='cv_qc_samples', folder=args.out_figures)\n", " print((qc_cv_feat < CV_QC_SAMPLE).value_counts())\n", " # only to ald_study data\n", " ald_study = ald_study[vaep.analyzers.diff_analysis.select_feat(qc_samples[ald_study.columns])]\n", - " \n", + "\n", "ald_study" ] }, @@ -360,8 +360,8 @@ "outputs": [], "source": [ "fig, axes = vaep.plotting.plot_cutoffs(observed.unstack(),\n", - " feat_completness_over_samples=cutoffs.feat_completness_over_samples,\n", - " min_feat_in_sample=cutoffs.min_feat_in_sample)\n", + " feat_completness_over_samples=cutoffs.feat_completness_over_samples,\n", + " min_feat_in_sample=cutoffs.min_feat_in_sample)\n", "vaep.savefig(fig, name='tresholds_normal_imputation', folder=args.out_figures)" ] }, @@ -399,7 +399,7 @@ "outputs": [], "source": [ "fname = args.out_preds / args.template_pred.format(args.model)\n", - "fname " + "fname" ] }, { @@ -462,7 +462,7 @@ "def plot_distributions(observed: pd.Series,\n", " imputation: pd.Series = None,\n", " model_key: str = 'MODEL',\n", - " figsize=(4,3),\n", + " figsize=(4, 3),\n", " sharex=True):\n", " \"\"\"Plots distributions of intensities provided as dictionary of labels to pd.Series.\"\"\"\n", " series_ = [observed, imputation] if imputation is not None else [observed]\n", @@ -474,8 +474,8 @@ " else:\n", " fig, ax = plt.subplots(1, figsize=figsize, sharex=sharex)\n", "\n", - " bins = range(min_bin, max_bin+1, 1)\n", - " \n", + " bins = range(min_bin, max_bin + 1, 1)\n", + "\n", " label = 'observed measurments'\n", " ax = observed.hist(ax=ax, bins=bins, color='grey')\n", " ax.set_title(f'{label} (N={len(observed):,d})')\n", @@ -483,14 +483,13 @@ " ax.locator_params(axis='y', integer=True)\n", " ax.yaxis.set_major_formatter(\"{x:,.0f}\")\n", "\n", - "\n", " if imputation is not None:\n", " ax = axes[1]\n", " label = f'Missing values imputed using {model_key.upper()}'\n", " color = vaep.plotting.defaults.color_model_mapping.get(model_key, None)\n", " if color is None:\n", " color = f'C{1}'\n", - " ax = imputation.hist(ax=ax,bins=bins, color=color)\n", + " ax = imputation.hist(ax=ax, bins=bins, color=color)\n", " ax.set_title(f'{label} (N={len(imputation):,d})')\n", " ax.set_ylabel('observations')\n", " ax.locator_params(axis='y', integer=True)\n", @@ -522,7 +521,7 @@ "source": [ "if pred_real_na is not None:\n", " shifts = (vaep.imputation.compute_moments_shift(observed, pred_real_na,\n", - " names=('observed', args.model_key)))\n", + " names=('observed', args.model_key)))\n", " display(pd.DataFrame(shifts).T)" ] }, @@ -543,8 +542,8 @@ " index_level = 0 # per sample\n", " mean_by_sample = pd.DataFrame(\n", " {'observed': vaep.imputation.stats_by_level(observed, index_level=index_level),\n", - " args.model_key: vaep.imputation.stats_by_level(pred_real_na, index_level=index_level)\n", - " })\n", + " args.model_key: vaep.imputation.stats_by_level(pred_real_na, index_level=index_level)\n", + " })\n", " mean_by_sample.loc['mean_shift'] = (mean_by_sample.loc['mean', 'observed'] -\n", " mean_by_sample.loc['mean']).abs() / mean_by_sample.loc['std', 'observed']\n", " mean_by_sample.loc['std shrinkage'] = mean_by_sample.loc['std'] / \\\n", @@ -602,10 +601,10 @@ "outputs": [], "source": [ "scores = vaep.stats.diff_analysis.analyze(df_proteomics=df,\n", - " df_clinic=df_clinic,\n", - " target=args.target,\n", - " covar=args.covar,\n", - " value_name=args.value_name)\n", + " df_clinic=df_clinic,\n", + " target=args.target,\n", + " covar=args.covar,\n", + " value_name=args.value_name)\n", "\n", "scores" ] @@ -623,7 +622,7 @@ " scores = (scores\n", " .join(gene_to_PG)\n", " .set_index(gene_to_PG.columns.to_list(), append=True)\n", - " )\n", + " )\n", "scores" ] }, @@ -648,7 +647,7 @@ }, "outputs": [], "source": [ - "fname = args.out_folder/ 'scores' / f'diff_analysis_scores_{str(args.model_key)}.pkl'\n", + "fname = args.out_folder / 'scores' / f'diff_analysis_scores_{str(args.model_key)}.pkl'\n", "files_out[fname.name] = fname.as_posix()\n", "fname.parent.mkdir(exist_ok=True, parents=True)\n", "scores.to_pickle(fname)\n", diff --git a/project/10_1_ald_diff_analysis.py b/project/10_1_ald_diff_analysis.py index cc5c3b6bb..15893ff5c 100644 --- a/project/10_1_ald_diff_analysis.py +++ b/project/10_1_ald_diff_analysis.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -17,7 +17,7 @@ # # - load missing values predictions # - leave all other values as they were -# - compare missing values predicition by model with baseline method +# - compare missing values predicition by model with baseline method # (default: draw from shifted normal distribution. short RSN) # %% @@ -48,19 +48,19 @@ folder_experiment = "runs/appl_ald_data/plasma/proteinGroups" folder_data: str = '' # specify data directory if needed fn_clinical_data = "data/ALD_study/processed/ald_metadata_cli.csv" -fn_qc_samples = '' #'data/ALD_study/processed/qc_plasma_proteinGroups.pkl' +fn_qc_samples = '' # 'data/ALD_study/processed/qc_plasma_proteinGroups.pkl' f_annotations = 'data/ALD_study/processed/ald_plasma_proteinGroups_id_mappings.csv' target: str = 'kleiner' -covar:str = 'age,bmi,gender_num,nas_steatosis_ordinal,abstinent_num' +covar: str = 'age,bmi,gender_num,nas_steatosis_ordinal,abstinent_num' file_format = "csv" -model_key = 'VAE' # model(s) to evaluate -model = None # default same as model_key, but could be overwritten (edge case) -value_name='intensity' -out_folder='diff_analysis' -template_pred = 'pred_real_na_{}.csv' # fixed, do not change +model_key = 'VAE' # model(s) to evaluate +model = None # default same as model_key, but could be overwritten (edge case) +value_name = 'intensity' +out_folder = 'diff_analysis' +template_pred = 'pred_real_na_{}.csv' # fixed, do not change # %% @@ -109,7 +109,7 @@ # %% df_clinic = pd.read_csv(args.fn_clinical_data, index_col=0) df_clinic = df_clinic.loc[observed.index.levels[0]] -cols_clinic = vaep.pandas.get_columns_accessor(df_clinic) # pick Berlin as reference? +cols_clinic = vaep.pandas.get_columns_accessor(df_clinic) df_clinic[[args.target, *args.covar]].describe() @@ -183,7 +183,7 @@ DATA_COMPLETENESS = 0.6 # MIN_N_PROTEIN_GROUPS: int = 200 FRAC_PROTEIN_GROUPS: int = 0.622 -CV_QC_SAMPLE: float = 0.4 # Coef. of variation on 13 QC samples +CV_QC_SAMPLE: float = 0.4 # Coef. of variation on 13 QC samples ald_study, cutoffs = vaep.analyzers.diff_analysis.select_raw_data(observed.unstack( ), data_completeness=DATA_COMPLETENESS, frac_protein_groups=FRAC_PROTEIN_GROUPS) @@ -196,20 +196,20 @@ qc_samples = pd.read_pickle(args.fn_qc_samples) qc_cv_feat = qc_samples.std() / qc_samples.mean() qc_cv_feat = qc_cv_feat.rename(qc_samples.columns.name) - fig, ax = plt.subplots(figsize=(4,7)) + fig, ax = plt.subplots(figsize=(4, 7)) ax = qc_cv_feat.plot.box(ax=ax) ax.set_ylabel('Coefficient of Variation') vaep.savefig(fig, name='cv_qc_samples', folder=args.out_figures) print((qc_cv_feat < CV_QC_SAMPLE).value_counts()) # only to ald_study data ald_study = ald_study[vaep.analyzers.diff_analysis.select_feat(qc_samples[ald_study.columns])] - + ald_study # %% fig, axes = vaep.plotting.plot_cutoffs(observed.unstack(), - feat_completness_over_samples=cutoffs.feat_completness_over_samples, - min_feat_in_sample=cutoffs.min_feat_in_sample) + feat_completness_over_samples=cutoffs.feat_completness_over_samples, + min_feat_in_sample=cutoffs.min_feat_in_sample) vaep.savefig(fig, name='tresholds_normal_imputation', folder=args.out_figures) @@ -225,7 +225,7 @@ # %% fname = args.out_preds / args.template_pred.format(args.model) -fname +fname # %% [markdown] # Baseline comparison @@ -262,7 +262,7 @@ def plot_distributions(observed: pd.Series, imputation: pd.Series = None, model_key: str = 'MODEL', - figsize=(4,3), + figsize=(4, 3), sharex=True): """Plots distributions of intensities provided as dictionary of labels to pd.Series.""" series_ = [observed, imputation] if imputation is not None else [observed] @@ -274,8 +274,8 @@ def plot_distributions(observed: pd.Series, else: fig, ax = plt.subplots(1, figsize=figsize, sharex=sharex) - bins = range(min_bin, max_bin+1, 1) - + bins = range(min_bin, max_bin + 1, 1) + label = 'observed measurments' ax = observed.hist(ax=ax, bins=bins, color='grey') ax.set_title(f'{label} (N={len(observed):,d})') @@ -283,14 +283,13 @@ def plot_distributions(observed: pd.Series, ax.locator_params(axis='y', integer=True) ax.yaxis.set_major_formatter("{x:,.0f}") - if imputation is not None: ax = axes[1] label = f'Missing values imputed using {model_key.upper()}' color = vaep.plotting.defaults.color_model_mapping.get(model_key, None) if color is None: color = f'C{1}' - ax = imputation.hist(ax=ax,bins=bins, color=color) + ax = imputation.hist(ax=ax, bins=bins, color=color) ax.set_title(f'{label} (N={len(imputation):,d})') ax.set_ylabel('observations') ax.locator_params(axis='y', integer=True) @@ -312,7 +311,7 @@ def plot_distributions(observed: pd.Series, # %% if pred_real_na is not None: shifts = (vaep.imputation.compute_moments_shift(observed, pred_real_na, - names=('observed', args.model_key))) + names=('observed', args.model_key))) display(pd.DataFrame(shifts).T) # %% [markdown] @@ -323,8 +322,8 @@ def plot_distributions(observed: pd.Series, index_level = 0 # per sample mean_by_sample = pd.DataFrame( {'observed': vaep.imputation.stats_by_level(observed, index_level=index_level), - args.model_key: vaep.imputation.stats_by_level(pred_real_na, index_level=index_level) - }) + args.model_key: vaep.imputation.stats_by_level(pred_real_na, index_level=index_level) + }) mean_by_sample.loc['mean_shift'] = (mean_by_sample.loc['mean', 'observed'] - mean_by_sample.loc['mean']).abs() / mean_by_sample.loc['std', 'observed'] mean_by_sample.loc['std shrinkage'] = mean_by_sample.loc['std'] / \ @@ -352,10 +351,10 @@ def plot_distributions(observed: pd.Series, # Targets - Clinical variables # %% scores = vaep.stats.diff_analysis.analyze(df_proteomics=df, - df_clinic=df_clinic, - target=args.target, - covar=args.covar, - value_name=args.value_name) + df_clinic=df_clinic, + target=args.target, + covar=args.covar, + value_name=args.value_name) scores @@ -366,7 +365,7 @@ def plot_distributions(observed: pd.Series, scores = (scores .join(gene_to_PG) .set_index(gene_to_PG.columns.to_list(), append=True) - ) + ) scores # %% @@ -376,7 +375,7 @@ def plot_distributions(observed: pd.Series, # %% -fname = args.out_folder/ 'scores' / f'diff_analysis_scores_{str(args.model_key)}.pkl' +fname = args.out_folder / 'scores' / f'diff_analysis_scores_{str(args.model_key)}.pkl' files_out[fname.name] = fname.as_posix() fname.parent.mkdir(exist_ok=True, parents=True) scores.to_pickle(fname) diff --git a/project/10_2_ald_compare_methods.ipynb b/project/10_2_ald_compare_methods.ipynb index e10ecbc66..68ad9f949 100644 --- a/project/10_2_ald_compare_methods.ipynb +++ b/project/10_2_ald_compare_methods.ipynb @@ -28,7 +28,7 @@ "logger = vaep.logging.setup_nb_logger()\n", "\n", "plt.rcParams['figure.figsize'] = (2, 2)\n", - "fontsize= 5\n", + "fontsize = 5\n", "vaep.plotting.make_large_descriptors(fontsize)" ] }, @@ -121,7 +121,7 @@ "source": [ "files_in = {\n", " 'freq_features_observed.csv': args.folder_experiment / 'freq_features_observed.csv',\n", - " }\n", + "}\n", "files_in" ] }, @@ -152,7 +152,7 @@ "source": [ "writer_args = dict(float_format='%.3f')\n", "\n", - "fname = args.out_folder / 'diff_analysis_compare_methods.xlsx'\n", + "fname = args.out_folder / 'diff_analysis_compare_methods.xlsx'\n", "files_out[fname.name] = fname\n", "writer = pd.ExcelWriter(fname)\n", "fname" @@ -163,7 +163,7 @@ "id": "770d1f76-e86f-4ae3-9d7b-ceef9b9e9a22", "metadata": {}, "source": [ - "# Load scores " + "# Load scores" ] }, { @@ -183,7 +183,7 @@ "metadata": {}, "outputs": [], "source": [ - "fname =args.scores_folder / f'diff_analysis_scores_{args.baseline}.pkl'\n", + "fname = args.scores_folder / f'diff_analysis_scores_{args.baseline}.pkl'\n", "scores_baseline = pd.read_pickle(fname)\n", "scores_baseline" ] @@ -259,11 +259,12 @@ "cell_type": "code", "execution_count": null, "id": "53bd5597-221c-4d54-abf2-82956db42594", - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ - "scores.describe(include=['bool', 'O'])\n", - "\n" + "scores.describe(include=['bool', 'O'])" ] }, { @@ -305,8 +306,8 @@ " .dropna()\n", " .reset_index(-1, drop=True)\n", " ).join(\n", - " freq_feat, how='left'\n", - " )\n", + " freq_feat, how='left'\n", + ")\n", "scores_common" ] }, @@ -323,7 +324,7 @@ "\n", "annotations = None\n", "for model, model_column in models.items():\n", - " if not annotations is None:\n", + " if annotations is not None:\n", " annotations += ' - '\n", " annotations += annotate_decision(scores_common,\n", " model=model, model_column=model_column)\n", @@ -395,7 +396,7 @@ "outputs": [], "source": [ "# should it be possible to run not only RSN?\n", - "to_plot['diff_qvalue'] = (to_plot[str(args.baseline)] - to_plot[str(args.model_key)]).abs()\n", + "to_plot['diff_qvalue'] = (to_plot[str(args.baseline)] - to_plot[str(args.model_key)]).abs()\n", "to_plot.loc[mask_different].sort_values('diff_qvalue', ascending=False)" ] }, @@ -430,7 +431,7 @@ "_ = ax.legend(fontsize=fontsize,\n", " title_fontsize=fontsize,\n", " markerscale=0.4,\n", - " title='',\n", + " title='',\n", " )\n", "ax.set_xlabel(f\"qvalue for {x_col}\")\n", "ax.set_ylabel(f\"qvalue for {y_col}\")\n", @@ -466,7 +467,7 @@ " y=to_plot.columns[1],\n", " size='frequency',\n", " s=size,\n", - " sizes=(5,20),\n", + " sizes=(5, 20),\n", " hue='Differential Analysis Comparison')\n", "_ = ax.legend(fontsize=fontsize,\n", " title_fontsize=fontsize,\n", @@ -504,7 +505,7 @@ " .loc[\n", " scores_model_only.index.difference(\n", " scores_common.index),\n", - " args.model_key]\n", + " args.model_key]\n", " .sort_values(by='qvalue', ascending=True)\n", " .join(freq_feat)\n", " )\n", @@ -592,7 +593,7 @@ "metadata": {}, "outputs": [], "source": [ - "feat_name = scores.index.names[0] # first index level is feature name\n", + "feat_name = scores.index.names[0] # first index level is feature name\n", "if args.annotaitons_gene_col in scores.index.names:\n", " logger.info(f\"Found gene annotation in scores index: {scores.index.names}\")\n", "else:\n", @@ -610,13 +611,13 @@ "outputs": [], "source": [ "gene_to_PG = (scores.droplevel(\n", - " list(set(scores.index.names) - {feat_name, args.annotaitons_gene_col})\n", - " )\n", - " .index\n", - " .to_frame()\n", - " .reset_index(drop=True)\n", - " .set_index(args.annotaitons_gene_col)\n", - " )\n", + " list(set(scores.index.names) - {feat_name, args.annotaitons_gene_col})\n", + ")\n", + " .index\n", + " .to_frame()\n", + " .reset_index(drop=True)\n", + " .set_index(args.annotaitons_gene_col)\n", + ")\n", "gene_to_PG.head()" ] }, diff --git a/project/10_2_ald_compare_methods.py b/project/10_2_ald_compare_methods.py index 5eac1e1ba..55037a3de 100644 --- a/project/10_2_ald_compare_methods.py +++ b/project/10_2_ald_compare_methods.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -29,7 +29,7 @@ logger = vaep.logging.setup_nb_logger() plt.rcParams['figure.figsize'] = (2, 2) -fontsize= 5 +fontsize = 5 vaep.plotting.make_large_descriptors(fontsize) # %% @@ -76,7 +76,7 @@ # %% files_in = { 'freq_features_observed.csv': args.folder_experiment / 'freq_features_observed.csv', - } +} files_in # %% [markdown] @@ -88,19 +88,19 @@ # %% writer_args = dict(float_format='%.3f') -fname = args.out_folder / 'diff_analysis_compare_methods.xlsx' +fname = args.out_folder / 'diff_analysis_compare_methods.xlsx' files_out[fname.name] = fname writer = pd.ExcelWriter(fname) fname # %% [markdown] -# # Load scores +# # Load scores # %% [x for x in args.scores_folder.iterdir() if 'scores' in str(x)] # %% -fname =args.scores_folder / f'diff_analysis_scores_{args.baseline}.pkl' +fname = args.scores_folder / f'diff_analysis_scores_{args.baseline}.pkl' scores_baseline = pd.read_pickle(fname) scores_baseline @@ -133,7 +133,6 @@ scores.describe(include=['bool', 'O']) - # %% [markdown] # ## Load frequencies of observed features @@ -150,8 +149,8 @@ .dropna() .reset_index(-1, drop=True) ).join( - freq_feat, how='left' - ) + freq_feat, how='left' +) scores_common @@ -162,7 +161,7 @@ def annotate_decision(scores, model, model_column): annotations = None for model, model_column in models.items(): - if not annotations is None: + if annotations is not None: annotations += ' - ' annotations += annotate_decision(scores_common, model=model, model_column=model_column) @@ -199,7 +198,7 @@ def annotate_decision(scores, model, model_column): # %% # should it be possible to run not only RSN? -to_plot['diff_qvalue'] = (to_plot[str(args.baseline)] - to_plot[str(args.model_key)]).abs() +to_plot['diff_qvalue'] = (to_plot[str(args.baseline)] - to_plot[str(args.model_key)]).abs() to_plot.loc[mask_different].sort_values('diff_qvalue', ascending=False) # %% [markdown] @@ -222,7 +221,7 @@ def annotate_decision(scores, model, model_column): _ = ax.legend(fontsize=fontsize, title_fontsize=fontsize, markerscale=0.4, - title='', + title='', ) ax.set_xlabel(f"qvalue for {x_col}") ax.set_ylabel(f"qvalue for {y_col}") @@ -246,7 +245,7 @@ def annotate_decision(scores, model, model_column): y=to_plot.columns[1], size='frequency', s=size, - sizes=(5,20), + sizes=(5, 20), hue='Differential Analysis Comparison') _ = ax.legend(fontsize=fontsize, title_fontsize=fontsize, @@ -272,7 +271,7 @@ def annotate_decision(scores, model, model_column): .loc[ scores_model_only.index.difference( scores_common.index), - args.model_key] + args.model_key] .sort_values(by='qvalue', ascending=True) .join(freq_feat) ) @@ -307,7 +306,7 @@ def annotate_decision(scores, model, model_column): # %% # %% -feat_name = scores.index.names[0] # first index level is feature name +feat_name = scores.index.names[0] # first index level is feature name if args.annotaitons_gene_col in scores.index.names: logger.info(f"Found gene annotation in scores index: {scores.index.names}") else: @@ -318,13 +317,13 @@ def annotate_decision(scores, model, model_column): # %% gene_to_PG = (scores.droplevel( - list(set(scores.index.names) - {feat_name, args.annotaitons_gene_col}) - ) - .index - .to_frame() - .reset_index(drop=True) - .set_index(args.annotaitons_gene_col) - ) + list(set(scores.index.names) - {feat_name, args.annotaitons_gene_col}) +) + .index + .to_frame() + .reset_index(drop=True) + .set_index(args.annotaitons_gene_col) +) gene_to_PG.head() # %% diff --git a/project/10_3_ald_ml_new_feat.ipynb b/project/10_3_ald_ml_new_feat.ipynb index dbb096e61..d3d7dd763 100644 --- a/project/10_3_ald_ml_new_feat.ipynb +++ b/project/10_3_ald_ml_new_feat.ipynb @@ -40,8 +40,8 @@ "\n", "plt.rcParams['figure.figsize'] = (2.5, 2.5)\n", "plt.rcParams['lines.linewidth'] = 1\n", - "fontsize= 5\n", - "figsize= (2.5, 2.5)\n", + "fontsize = 5\n", + "figsize = (2.5, 2.5)\n", "vaep.plotting.make_large_descriptors(fontsize)\n", "\n", "\n", @@ -89,7 +89,7 @@ "cutoff_target: int = 2 # => for binarization target >= cutoff_target\n", "file_format = \"csv\"\n", "out_folder = 'diff_analysis'\n", - "fn_qc_samples = '' #'data/ALD_study/processed/qc_plasma_proteinGroups.pkl'\n", + "fn_qc_samples = '' # 'data/ALD_study/processed/qc_plasma_proteinGroups.pkl'\n", "\n", "baseline = 'RSN' # default is RSN, as this was used in the original ALD Niu. et. al 2022\n", "template_pred = 'pred_real_na_{}.csv' # fixed, do not change" @@ -272,7 +272,7 @@ "outputs": [], "source": [ "fname = args.out_preds / args.template_pred.format(args.baseline)\n", - "pred_real_na_baseline = load_single_csv_pred_file(fname) #.loc[mask_has_target]\n", + "pred_real_na_baseline = load_single_csv_pred_file(fname) # .loc[mask_has_target]\n", "pred_real_na_baseline" ] }, @@ -291,7 +291,9 @@ "Repeat general approach for\n", " 1. all original ald data: all features justed in original ALD study\n", " 2. all model data: all features available my using the self supervised deep learning model\n", - " 3. newly available feat only: the subset of features available from the self supervised deep learning model which were newly retained using the new approach" + "3. newly available feat only: the subset of features available from the\n", + "self supervised deep learning model which were newly retained using the\n", + "new approach" ] }, { diff --git a/project/10_3_ald_ml_new_feat.py b/project/10_3_ald_ml_new_feat.py index fca637f80..5ac862558 100644 --- a/project/10_3_ald_ml_new_feat.py +++ b/project/10_3_ald_ml_new_feat.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -41,8 +41,8 @@ plt.rcParams['figure.figsize'] = (2.5, 2.5) plt.rcParams['lines.linewidth'] = 1 -fontsize= 5 -figsize= (2.5, 2.5) +fontsize = 5 +figsize = (2.5, 2.5) vaep.plotting.make_large_descriptors(fontsize) @@ -66,7 +66,7 @@ cutoff_target: int = 2 # => for binarization target >= cutoff_target file_format = "csv" out_folder = 'diff_analysis' -fn_qc_samples = '' #'data/ALD_study/processed/qc_plasma_proteinGroups.pkl' +fn_qc_samples = '' # 'data/ALD_study/processed/qc_plasma_proteinGroups.pkl' baseline = 'RSN' # default is RSN, as this was used in the original ALD Niu. et. al 2022 template_pred = 'pred_real_na_{}.csv' # fixed, do not change @@ -160,7 +160,7 @@ # %% fname = args.out_preds / args.template_pred.format(args.baseline) -pred_real_na_baseline = load_single_csv_pred_file(fname) #.loc[mask_has_target] +pred_real_na_baseline = load_single_csv_pred_file(fname) # .loc[mask_has_target] pred_real_na_baseline # %% [markdown] @@ -174,7 +174,9 @@ # Repeat general approach for # 1. all original ald data: all features justed in original ALD study # 2. all model data: all features available my using the self supervised deep learning model -# 3. newly available feat only: the subset of features available from the self supervised deep learning model which were newly retained using the new approach +# 3. newly available feat only: the subset of features available from the +# self supervised deep learning model which were newly retained using the +# new approach # %% X = pd.concat([data, pred_real_na]).unstack() diff --git a/project/10_4_ald_compare_single_pg.ipynb b/project/10_4_ald_compare_single_pg.ipynb index a5e0612f1..80ea04a41 100644 --- a/project/10_4_ald_compare_single_pg.ipynb +++ b/project/10_4_ald_compare_single_pg.ipynb @@ -72,7 +72,7 @@ "source": [ "folder_experiment = 'runs/appl_ald_data/plasma/proteinGroups'\n", "fn_clinical_data = \"data/ALD_study/processed/ald_metadata_cli.csv\"\n", - "make_plots = True # create histograms and swarmplots of diverging results\n", + "make_plots = True # create histograms and swarmplots of diverging results\n", "model_key = 'VAE'\n", "sample_id_col = 'Sample ID'\n", "target = 'kleiner'\n", @@ -81,7 +81,7 @@ "file_format = 'csv'\n", "baseline = 'RSN' # default is RSN, but could be any other trained model\n", "template_pred = 'pred_real_na_{}.csv' # fixed, do not change\n", - "ref_method_score = None # filepath to reference method score" + "ref_method_score = None # filepath to reference method score" ] }, { @@ -164,7 +164,7 @@ "outputs": [], "source": [ "# Reference dump\n", - "if args.ref_method_score: \n", + "if args.ref_method_score:\n", " scores_reference = (pd\n", " .read_pickle(args.ref_method_score)\n", " .rename({'None': 'None (100%)'},\n", @@ -207,7 +207,7 @@ " ).set_index(\n", " ('data', 'frequency'), append=True)\n", "qvalues.index.names = qvalues.index.names[:-1] + ['frequency']\n", - "fname = args.out_folder / 'qvalues_target.pkl'\n", + "fname = args.out_folder / 'qvalues_target.pkl'\n", "files_out[fname.name] = fname.as_posix()\n", "qvalues.to_pickle(fname)\n", "qvalues.to_excel(writer, sheet_name='qvalues_all')\n", @@ -227,7 +227,7 @@ " ).set_index(\n", " ('data', 'frequency'), append=True)\n", "pvalues.index.names = pvalues.index.names[:-1] + ['frequency']\n", - "fname = args.out_folder / 'pvalues_target.pkl'\n", + "fname = args.out_folder / 'pvalues_target.pkl'\n", "files_out[fname.name] = fname.as_posix()\n", "pvalues.to_pickle(fname)\n", "pvalues.to_excel(writer, sheet_name='pvalues_all')\n", @@ -244,7 +244,7 @@ "da_target = scores.loc[pd.IndexSlice[:, args.target],\n", " pd.IndexSlice[:, 'rejected']\n", " ].join(freq_feat\n", - " ).set_index(\n", + " ).set_index(\n", " ('data', 'frequency'), append=True)\n", "da_target.index.names = da_target.index.names[:-1] + ['frequency']\n", "fname = args.out_folder / 'equality_rejected_target.pkl'\n", @@ -677,7 +677,7 @@ " fig, ax = plt.subplots()\n", "\n", " # dummy plots, just to get the Path objects\n", - " tmp_dot = ax.scatter([1,2],[3,4], marker='X')\n", + " tmp_dot = ax.scatter([1, 2], [3, 4], marker='X')\n", " new_mk, = tmp_dot.get_paths()\n", " tmp_dot.remove()\n", "\n", diff --git a/project/10_4_ald_compare_single_pg.py b/project/10_4_ald_compare_single_pg.py index 7b3c9279c..925568114 100644 --- a/project/10_4_ald_compare_single_pg.py +++ b/project/10_4_ald_compare_single_pg.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -49,7 +49,7 @@ # %% tags=["parameters"] folder_experiment = 'runs/appl_ald_data/plasma/proteinGroups' fn_clinical_data = "data/ALD_study/processed/ald_metadata_cli.csv" -make_plots = True # create histograms and swarmplots of diverging results +make_plots = True # create histograms and swarmplots of diverging results model_key = 'VAE' sample_id_col = 'Sample ID' target = 'kleiner' @@ -58,7 +58,7 @@ file_format = 'csv' baseline = 'RSN' # default is RSN, but could be any other trained model template_pred = 'pred_real_na_{}.csv' # fixed, do not change -ref_method_score = None # filepath to reference method score +ref_method_score = None # filepath to reference method score # %% @@ -99,7 +99,7 @@ # %% # Reference dump -if args.ref_method_score: +if args.ref_method_score: scores_reference = (pd .read_pickle(args.ref_method_score) .rename({'None': 'None (100%)'}, @@ -123,7 +123,7 @@ ).set_index( ('data', 'frequency'), append=True) qvalues.index.names = qvalues.index.names[:-1] + ['frequency'] -fname = args.out_folder / 'qvalues_target.pkl' +fname = args.out_folder / 'qvalues_target.pkl' files_out[fname.name] = fname.as_posix() qvalues.to_pickle(fname) qvalues.to_excel(writer, sheet_name='qvalues_all') @@ -136,7 +136,7 @@ ).set_index( ('data', 'frequency'), append=True) pvalues.index.names = pvalues.index.names[:-1] + ['frequency'] -fname = args.out_folder / 'pvalues_target.pkl' +fname = args.out_folder / 'pvalues_target.pkl' files_out[fname.name] = fname.as_posix() pvalues.to_pickle(fname) pvalues.to_excel(writer, sheet_name='pvalues_all') @@ -146,7 +146,7 @@ da_target = scores.loc[pd.IndexSlice[:, args.target], pd.IndexSlice[:, 'rejected'] ].join(freq_feat - ).set_index( + ).set_index( ('data', 'frequency'), append=True) da_target.index.names = da_target.index.names[:-1] + ['frequency'] fname = args.out_folder / 'equality_rejected_target.pkl' @@ -378,7 +378,7 @@ fig, ax = plt.subplots() # dummy plots, just to get the Path objects - tmp_dot = ax.scatter([1,2],[3,4], marker='X') + tmp_dot = ax.scatter([1, 2], [3, 4], marker='X') new_mk, = tmp_dot.get_paths() tmp_dot.remove() diff --git a/project/10_5_comp_diff_analysis_repetitions.ipynb b/project/10_5_comp_diff_analysis_repetitions.ipynb index 961dd02c0..0d09578be 100644 --- a/project/10_5_comp_diff_analysis_repetitions.ipynb +++ b/project/10_5_comp_diff_analysis_repetitions.ipynb @@ -27,9 +27,7 @@ "cell_type": "code", "execution_count": null, "id": "8bef6cd3-fef6-4499-85cb-63bd524c9edc", - "metadata": { - "lines_to_next_cell": 1 - }, + "metadata": {}, "outputs": [], "source": [ "files_out = dict()\n", @@ -46,15 +44,18 @@ "metadata": {}, "outputs": [], "source": [ - "def _load_pickle(pfath, run:int):\n", + "\n", + "\n", + "def _load_pickle(pfath, run: int):\n", " df = pd.read_pickle(pfath)\n", " df['run'] = f'run{run:02d}'\n", " df = df.set_index('run', append=True)\n", " return df\n", "\n", + "\n", "df_long_qvalues = pd.concat(\n", - " [_load_pickle(f,i) for i,f in enumerate(pickled_qvalues)]\n", - " )\n", + " [_load_pickle(f, i) for i, f in enumerate(pickled_qvalues)]\n", + ")\n", "df_long_qvalues" ] }, @@ -148,7 +149,7 @@ " [~da_target_same]\n", " .index\n", " .get_level_values(0)\n", - ")" + " )" ] }, { @@ -181,7 +182,7 @@ "qvalue_stats = (qvalue_stats\n", " .loc[idx_different]\n", " .sort_values(('None', 'qvalue', 'mean'))\n", - ")\n", + " )\n", "qvalue_stats" ] }, @@ -254,15 +255,15 @@ "source": [ "# pgs included in original ald study\n", "tab_diff_rejec_counts_old = (da_counts\n", - " .loc[mask_pgs_included_in_ald_study]\n", - " .reset_index()\n", - " .groupby(\n", - " by=da_counts.columns.to_list())\n", - " .size()\n", - " .to_frame('N')\n", - ")\n", + " .loc[mask_pgs_included_in_ald_study]\n", + " .reset_index()\n", + " .groupby(\n", + " by=da_counts.columns.to_list())\n", + " .size()\n", + " .to_frame('N')\n", + " )\n", "tab_diff_rejec_counts_old.to_excel(writer,\n", - " sheet_name='tab_diff_rejec_counts_old')\n", + " sheet_name='tab_diff_rejec_counts_old')\n", "tab_diff_rejec_counts_old" ] }, @@ -292,17 +293,16 @@ "source": [ "# new pgs\n", "tab_diff_rejec_counts_new = (da_counts\n", - " .loc[~mask_pgs_included_in_ald_study]\n", - " .reset_index()\n", - " .drop('RSN', axis=1)\n", - " .groupby(\n", - " by=\n", - " [m for m in da_counts.columns if m != 'RSN'])\n", - " .size()\n", - " .to_frame('N')\n", - ")\n", + " .loc[~mask_pgs_included_in_ald_study]\n", + " .reset_index()\n", + " .drop('RSN', axis=1)\n", + " .groupby(\n", + " by=[m for m in da_counts.columns if m != 'RSN'])\n", + " .size()\n", + " .to_frame('N')\n", + " )\n", "tab_diff_rejec_counts_new.to_excel(writer,\n", - " sheet_name='tab_diff_rejec_counts_new')\n", + " sheet_name='tab_diff_rejec_counts_new')\n", "tab_diff_rejec_counts_new" ] }, @@ -331,7 +331,7 @@ "outputs": [], "source": [ "mask_new_da_with_imp = mask_new_da_with_imputation = ((~mask_pgs_included_in_ald_study)\n", - " & (da_counts['None'] != 10))\n", + " & (da_counts['None'] != 10))\n", "\n", "tab_new_da_with_imp = vaep.pandas.combine_value_counts(\n", " da_counts\n", diff --git a/project/10_5_comp_diff_analysis_repetitions.py b/project/10_5_comp_diff_analysis_repetitions.py index 65df744be..909c940fd 100644 --- a/project/10_5_comp_diff_analysis_repetitions.py +++ b/project/10_5_comp_diff_analysis_repetitions.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: vaep # language: python @@ -29,15 +29,18 @@ fname # %% -def _load_pickle(pfath, run:int): + + +def _load_pickle(pfath, run: int): df = pd.read_pickle(pfath) df['run'] = f'run{run:02d}' df = df.set_index('run', append=True) return df + df_long_qvalues = pd.concat( - [_load_pickle(f,i) for i,f in enumerate(pickled_qvalues)] - ) + [_load_pickle(f, i) for i, f in enumerate(pickled_qvalues)] +) df_long_qvalues # %% [markdown] @@ -77,7 +80,7 @@ def _load_pickle(pfath, run:int): [~da_target_same] .index .get_level_values(0) -) + ) # %% da_counts = da_counts.loc[idx_different] @@ -90,7 +93,7 @@ def _load_pickle(pfath, run:int): qvalue_stats = (qvalue_stats .loc[idx_different] .sort_values(('None', 'qvalue', 'mean')) -) + ) qvalue_stats # %% [markdown] @@ -123,15 +126,15 @@ def _load_pickle(pfath, run:int): # %% # pgs included in original ald study tab_diff_rejec_counts_old = (da_counts - .loc[mask_pgs_included_in_ald_study] - .reset_index() - .groupby( - by=da_counts.columns.to_list()) - .size() - .to_frame('N') -) + .loc[mask_pgs_included_in_ald_study] + .reset_index() + .groupby( + by=da_counts.columns.to_list()) + .size() + .to_frame('N') + ) tab_diff_rejec_counts_old.to_excel(writer, - sheet_name='tab_diff_rejec_counts_old') + sheet_name='tab_diff_rejec_counts_old') tab_diff_rejec_counts_old # %% @@ -147,17 +150,16 @@ def _load_pickle(pfath, run:int): # %% # new pgs tab_diff_rejec_counts_new = (da_counts - .loc[~mask_pgs_included_in_ald_study] - .reset_index() - .drop('RSN', axis=1) - .groupby( - by= - [m for m in da_counts.columns if m != 'RSN']) - .size() - .to_frame('N') -) + .loc[~mask_pgs_included_in_ald_study] + .reset_index() + .drop('RSN', axis=1) + .groupby( + by=[m for m in da_counts.columns if m != 'RSN']) + .size() + .to_frame('N') + ) tab_diff_rejec_counts_new.to_excel(writer, - sheet_name='tab_diff_rejec_counts_new') + sheet_name='tab_diff_rejec_counts_new') tab_diff_rejec_counts_new # %% @@ -172,7 +174,7 @@ def _load_pickle(pfath, run:int): # %% mask_new_da_with_imp = mask_new_da_with_imputation = ((~mask_pgs_included_in_ald_study) - & (da_counts['None'] != 10)) + & (da_counts['None'] != 10)) tab_new_da_with_imp = vaep.pandas.combine_value_counts( da_counts diff --git a/project/10_6_interpret_repeated_ald_da.py b/project/10_6_interpret_repeated_ald_da.py index b9cc384ed..bb685cb21 100644 --- a/project/10_6_interpret_repeated_ald_da.py +++ b/project/10_6_interpret_repeated_ald_da.py @@ -24,7 +24,7 @@ def load_pred_from_run(run_folder: Path, # %% reps_folder = 'runs/appl_ald_data/plasma/proteinGroups/reps' template_pred = 'pred_real_na_{}.csv' # fixed, do not change -model_keys = ['CF', 'DAE', 'KNN', 'Median', 'RSN', 'VAE','rf'] +model_keys = ['CF', 'DAE', 'KNN', 'Median', 'RSN', 'VAE', 'rf'] # %% @@ -52,12 +52,12 @@ def load_pred_from_run(run_folder: Path, for method in model_keys: pred_real_na_cvs[method] = pred_real_na[( method, 'std')] / pred_real_na[(method, 'mean')] - + pred_real_na_cvs.to_excel(writer, float_format='%.3f', sheet_name='CVs') ax = pred_real_na_cvs.plot.hist(bins=15, color=vaep.plotting.defaults.assign_colors(model_keys), - alpha=0.5) + alpha=0.5) ax.yaxis.set_major_formatter('{x:,.0f}') ax.set_xlabel(f'Coefficient of variation of imputed intensites (N={len(pred_real_na):,d})') fname = reps_folder / 'pred_real_na_cvs.png' diff --git a/project/10_7_ald_reduced_dataset_plots.ipynb b/project/10_7_ald_reduced_dataset_plots.ipynb index af290974c..3c6f8b974 100644 --- a/project/10_7_ald_reduced_dataset_plots.ipynb +++ b/project/10_7_ald_reduced_dataset_plots.ipynb @@ -25,6 +25,7 @@ "\n", "COLORS_TO_USE_MAPPTING = vaep.plotting.defaults.color_model_mapping\n", "\n", + "\n", "def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05,\n", " alpha=1.0, style='.', markersize=3):\n", " ax = df.plot.line(x=x,\n", @@ -40,14 +41,15 @@ " linestyles='dashed',\n", " color='grey',\n", " linewidth=1)\n", - " return ax\n", - "\n" + " return ax" ] }, { "cell_type": "markdown", "id": "9d21e1a1-7a46-49d4-8976-bc2031652ee4", - "metadata": {}, + "metadata": { + "lines_to_next_cell": 0 + }, "source": [ "DA analysis" ] @@ -219,7 +221,7 @@ "source": [ "mask_lost_sign = (\n", " (da_target_sel['None'] == False)\n", - " & (da_target_sel[REF_MODEL] == True)\n", + " & (da_target_sel[REF_MODEL])\n", ")\n", "sel = qvalues_sel.loc[mask_lost_sign.squeeze()]\n", "sel.columns = sel.columns.droplevel(-1)\n", @@ -238,12 +240,12 @@ "# 0: FN\n", "# 1: TP\n", "da_target_sel_counts = (da_target_sel[ORDER_MODELS]\n", - " .loc[mask_lost_sign.squeeze()]\n", - " .astype(int)\n", - " .replace(\n", - " {0: 'FN',\n", - " 1: 'TP'}\n", - " ).droplevel(-1, axis=1)\n", + " .loc[mask_lost_sign.squeeze()]\n", + " .astype(int)\n", + " .replace(\n", + " {0: 'FN',\n", + " 1: 'TP'}\n", + ").droplevel(-1, axis=1)\n", ")\n", "da_target_sel_counts = vaep.pandas.combine_value_counts(da_target_sel_counts)\n", "ax = da_target_sel_counts.T.plot.bar()\n", @@ -290,7 +292,7 @@ "outputs": [], "source": [ "mask_gained_signal = (\n", - " (da_target_sel['None'] == True)\n", + " (da_target_sel['None'])\n", " & (da_target_sel[REF_MODEL] == False)\n", ")\n", "sel = qvalues_sel.loc[mask_gained_signal.squeeze()]\n", @@ -308,12 +310,12 @@ "outputs": [], "source": [ "da_target_sel_counts = (da_target_sel[ORDER_MODELS]\n", - " .loc[mask_gained_signal.squeeze()]\n", - " .astype(int)\n", - " .replace(\n", - " {0: 'TN',\n", - " 1: 'FP'}\n", - " ).droplevel(-1, axis=1)\n", + " .loc[mask_gained_signal.squeeze()]\n", + " .astype(int)\n", + " .replace(\n", + " {0: 'TN',\n", + " 1: 'FP'}\n", + ").droplevel(-1, axis=1)\n", ")\n", "da_target_sel_counts = vaep.pandas.combine_value_counts(da_target_sel_counts)\n", "ax = da_target_sel_counts.T.plot.bar()\n", diff --git a/project/10_7_ald_reduced_dataset_plots.py b/project/10_7_ald_reduced_dataset_plots.py index 670f3a057..e62ffe87a 100644 --- a/project/10_7_ald_reduced_dataset_plots.py +++ b/project/10_7_ald_reduced_dataset_plots.py @@ -12,6 +12,7 @@ COLORS_TO_USE_MAPPTING = vaep.plotting.defaults.color_model_mapping + def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, alpha=1.0, style='.', markersize=3): ax = df.plot.line(x=x, @@ -30,10 +31,8 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, return ax - # %% [markdown] # DA analysis - # %% out_folder = 'runs/appl_ald_data/plasma/proteinGroups_80%_dataset/diff_analysis/kleiner/' out_folder = Path(out_folder) @@ -102,7 +101,7 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, # %% mask_lost_sign = ( (da_target_sel['None'] == False) - & (da_target_sel[REF_MODEL] == True) + & (da_target_sel[REF_MODEL]) ) sel = qvalues_sel.loc[mask_lost_sign.squeeze()] sel.columns = sel.columns.droplevel(-1) @@ -114,12 +113,12 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, # 0: FN # 1: TP da_target_sel_counts = (da_target_sel[ORDER_MODELS] - .loc[mask_lost_sign.squeeze()] - .astype(int) - .replace( - {0: 'FN', - 1: 'TP'} - ).droplevel(-1, axis=1) + .loc[mask_lost_sign.squeeze()] + .astype(int) + .replace( + {0: 'FN', + 1: 'TP'} +).droplevel(-1, axis=1) ) da_target_sel_counts = vaep.pandas.combine_value_counts(da_target_sel_counts) ax = da_target_sel_counts.T.plot.bar() @@ -146,7 +145,7 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, # %% mask_gained_signal = ( - (da_target_sel['None'] == True) + (da_target_sel['None']) & (da_target_sel[REF_MODEL] == False) ) sel = qvalues_sel.loc[mask_gained_signal.squeeze()] @@ -157,12 +156,12 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, # %% da_target_sel_counts = (da_target_sel[ORDER_MODELS] - .loc[mask_gained_signal.squeeze()] - .astype(int) - .replace( - {0: 'TN', - 1: 'FP'} - ).droplevel(-1, axis=1) + .loc[mask_gained_signal.squeeze()] + .astype(int) + .replace( + {0: 'TN', + 1: 'FP'} +).droplevel(-1, axis=1) ) da_target_sel_counts = vaep.pandas.combine_value_counts(da_target_sel_counts) ax = da_target_sel_counts.T.plot.bar() diff --git a/project/erda_00_maxquant_file_reader.ipynb b/project/erda_00_maxquant_file_reader.ipynb index 26b0e9ac8..d4bcd42d9 100644 --- a/project/erda_00_maxquant_file_reader.ipynb +++ b/project/erda_00_maxquant_file_reader.ipynb @@ -50,14 +50,14 @@ "from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED\n", "from config import FOLDER_KEY # defines how filenames are parsed for use as indices\n", "\n", - "from config import FOLDER_DATA # project folder for storing the data\n", + "from config import FOLDER_DATA # project folder for storing the data\n", "print(f\"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}\")\n", "\n", "##################\n", "### Logging ######\n", "##################\n", "\n", - "#Delete Jupyter notebook root logger handler\n", + "# Delete Jupyter notebook root logger handler\n", "root_logger = logging.getLogger()\n", "root_logger.handlers = []\n", "\n", @@ -73,7 +73,7 @@ "metadata": {}, "outputs": [], "source": [ - "folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir()]" + "folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir()]" ] }, { @@ -82,7 +82,7 @@ "metadata": {}, "outputs": [], "source": [ - "folders_dict = {folder.name: folder for folder in sorted(folders) }\n", + "folders_dict = {folder.name: folder for folder in sorted(folders)}\n", "assert len(folders_dict) == len(folders), \"Non unique file names\"" ] }, @@ -113,7 +113,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Results will be saved in a subfolder under `vaep/project/data` using the name of the specified input-folder per default. Change to your liking:" + "Results will be saved in a subfolder under `vaep/project/data` using the\n", + "name of the specified input-folder per default. Change to your liking:" ] }, { @@ -172,7 +173,7 @@ "source": [ "### Summaries\n", "\n", - "- aggregated in `vaep/project/erda_01_mq_aggregate_summaries.ipynb` \n", + "- aggregated in `vaep/project/erda_01_mq_aggregate_summaries.ipynb`\n", " - file selection based on summaries for further analysis thereafter" ] }, @@ -258,8 +259,8 @@ "source": [ "mqpar_files = (Path(FOLDER_DATA) / 'mqpar_files')\n", "\n", - "mqpar_files = [file for file in mqpar_files.iterdir() if file.suffix == '.xml']\n", - "len(mqpar_files) # nested search needed" + "mqpar_files = [file for file in mqpar_files.iterdir() if file.suffix == '.xml']\n", + "len(mqpar_files) # nested search needed" ] }, { @@ -296,8 +297,8 @@ "d_mqpar = dict()\n", "for file in tqdm(mqpar_files):\n", " d_mqpar[file.stem] = load_mqpar_xml(file)['MaxQuantParams']\n", - " \n", - "df_mqpar = pd.DataFrame(d_mqpar.values() , index=d_mqpar.keys()).convert_dtypes()\n", + "\n", + "df_mqpar = pd.DataFrame(d_mqpar.values(), index=d_mqpar.keys()).convert_dtypes()\n", "df_mqpar" ] }, @@ -340,7 +341,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "in order to see if there are different setting based on the string columns, drop duplicates \n", + "in order to see if there are different setting based on the string columns, drop duplicates\n", "\n", "- only one should remain" ] @@ -396,7 +397,7 @@ "metadata": {}, "outputs": [], "source": [ - "mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands" + "mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands" ] }, { diff --git a/project/erda_00_maxquant_file_reader.py b/project/erda_00_maxquant_file_reader.py index f441a31ac..74e572164 100644 --- a/project/erda_00_maxquant_file_reader.py +++ b/project/erda_00_maxquant_file_reader.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 (ipykernel) # language: python @@ -51,14 +51,14 @@ from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED from config import FOLDER_KEY # defines how filenames are parsed for use as indices -from config import FOLDER_DATA # project folder for storing the data +from config import FOLDER_DATA # project folder for storing the data print(f"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}") ################## ### Logging ###### ################## -#Delete Jupyter notebook root logger handler +# Delete Jupyter notebook root logger handler root_logger = logging.getLogger() root_logger.handlers = [] @@ -68,10 +68,10 @@ logger.info('Start with handlers: \n' + "\n".join(f"- {repr(log_)}" for log_ in logger.handlers)) # %% -folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir()] +folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir()] # %% -folders_dict = {folder.name: folder for folder in sorted(folders) } +folders_dict = {folder.name: folder for folder in sorted(folders)} assert len(folders_dict) == len(folders), "Non unique file names" # %% Collapsed="false" @@ -84,7 +84,8 @@ mq_output # %% [markdown] -# Results will be saved in a subfolder under `vaep/project/data` using the name of the specified input-folder per default. Change to your liking: +# Results will be saved in a subfolder under `vaep/project/data` using the +# name of the specified input-folder per default. Change to your liking: # %% [markdown] # > Go to the block you are interested in! @@ -107,7 +108,7 @@ # %% [markdown] Collapsed="false" # ### Summaries # -# - aggregated in `vaep/project/erda_01_mq_aggregate_summaries.ipynb` +# - aggregated in `vaep/project/erda_01_mq_aggregate_summaries.ipynb` # - file selection based on summaries for further analysis thereafter # %% @@ -152,8 +153,8 @@ # %% mqpar_files = (Path(FOLDER_DATA) / 'mqpar_files') -mqpar_files = [file for file in mqpar_files.iterdir() if file.suffix == '.xml'] -len(mqpar_files) # nested search needed +mqpar_files = [file for file in mqpar_files.iterdir() if file.suffix == '.xml'] +len(mqpar_files) # nested search needed # %% Collapsed="false" w_file = widgets.Dropdown(options=mqpar_files, description='Select a file') @@ -168,8 +169,8 @@ d_mqpar = dict() for file in tqdm(mqpar_files): d_mqpar[file.stem] = load_mqpar_xml(file)['MaxQuantParams'] - -df_mqpar = pd.DataFrame(d_mqpar.values() , index=d_mqpar.keys()).convert_dtypes() + +df_mqpar = pd.DataFrame(d_mqpar.values(), index=d_mqpar.keys()).convert_dtypes() df_mqpar # %% [markdown] @@ -188,7 +189,7 @@ df_mqpar.iloc[0].loc['fastaFiles'] # %% [markdown] -# in order to see if there are different setting based on the string columns, drop duplicates +# in order to see if there are different setting based on the string columns, drop duplicates # # - only one should remain @@ -212,7 +213,7 @@ mq_output.evidence # %% -mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands +mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands # %% [markdown] Collapsed="false" # ### Create peptide intensity dumps for each MQ outputfolder diff --git a/project/erda_01_mq_select_runs.ipynb b/project/erda_01_mq_select_runs.ipynb index af7dd493a..875fcb525 100644 --- a/project/erda_01_mq_select_runs.ipynb +++ b/project/erda_01_mq_select_runs.ipynb @@ -23,11 +23,22 @@ "metadata": {}, "outputs": [], "source": [ - "import sys\n", "import logging\n", "from pathlib import Path, PurePosixPath\n", "import yaml\n", - "import random\n", + "\n", + "import ipywidgets as widgets\n", + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from vaep.io.data_objects import MqAllSummaries\n", + "from vaep import plotting\n", + "from vaep.io.mq import MaxQuantOutputDynamic\n", + "\n", + "import config\n", + "from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED\n", + "\n", "\n", "##################\n", "### Logging ######\n", @@ -40,31 +51,18 @@ "\n", "logging.info('Start with handlers: \\n' + \"\\n\".join(f\"- {repr(log_)}\" for log_ in logger.handlers))\n", "\n", - "### Other imports\n", + "# Other imports\n", "\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pandas as pd\n", - "import ipywidgets as widgets\n", - "\n", - "from vaep.io.mq import MaxQuantOutputDynamic\n", - "from vaep import plotting\n", - "\n", - "from vaep.io import data_objects\n", - "from vaep.io.data_objects import MqAllSummaries \n", "\n", "##################\n", "##### CONFIG #####\n", "##################\n", - "import config\n", - "from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED\n", "\n", "ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml')\n", "MAP_FOLDER_PATH = Path('config/file_paths')\n", "FPATH_ALL_SUMMARIES = FOLDER_PROCESSED / 'all_summaries.json'\n", "FN_RAWFILE_METADATA = 'data/rawfile_metadata.csv'\n", "\n", - "from config import FOLDER_DATA # project folder for storing the data\n", "logger.info(f\"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}\")" ] }, @@ -76,7 +74,8 @@ }, "outputs": [], "source": [ - "folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir() and not folder.name.startswith('.')]" + "folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir()\n", + " and not folder.name.startswith('.')]" ] }, { @@ -91,7 +90,7 @@ "assert len(folders_dict) == len(folders), \"Non unique file names\"\n", "\n", "with open(MAP_FOLDER_PATH, 'w') as f:\n", - " yaml.dump({ k: str(PurePosixPath(v)) for k, v in folders_dict.items()} , f)\n", + " yaml.dump({k: str(PurePosixPath(v)) for k, v in folders_dict.items()}, f)\n", "logger.info(f\"Save map of file names to file paths to: {str(MAP_FOLDER_PATH)}\")\n", "\n", "# w_file = widgets.Dropdown(options=[folder for folder in folders], description='View files')\n", @@ -199,18 +198,19 @@ "source": [ "class col_summary:\n", " MS1 = 'MS'\n", - " MS2 = 'MS/MS' \n", - " MS2_identified = 'MS/MS Identified'\n", - " peptides_identified = 'Peptide Sequences Identified' # 'peptides.txt' should have this number of peptides\n", + " MS2 = 'MS/MS'\n", + " MS2_identified = 'MS/MS Identified'\n", + " peptides_identified = 'Peptide Sequences Identified' # 'peptides.txt' should have this number of peptides\n", + "\n", "\n", "df = mq_all_summaries.df\n", "if df is not None:\n", " MS_spectra = df[[col_summary.MS1, col_summary.MS2, col_summary.MS2_identified, col_summary.peptides_identified]]\n", "\n", " def compute_summary(threshold_identified):\n", - " mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified\n", + " mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified\n", " display(MS_spectra.loc[mask].describe(np.linspace(0.05, 0.95, 10)))\n", - " \n", + "\n", " w_ions_range = widgets.IntSlider(value=15_000, min=.0, max=MS_spectra[col_summary.peptides_identified].max())\n", " display(widgets.interactive(compute_summary, threshold_identified=w_ions_range))" ] @@ -221,10 +221,10 @@ "metadata": {}, "outputs": [], "source": [ - "mask = MS_spectra[col_summary.peptides_identified] >= w_ions_range.value\n", + "mask = MS_spectra[col_summary.peptides_identified] >= w_ions_range.value\n", "logger.warning(f\"Save {mask.sum()} file names to configuration file of selected samples: \"\n", - "f\"{ELIGABLE_FILES_YAML} \"\n", - "f\"based on a minimum of {w_ions_range.value} peptides.\")\n", + " f\"{ELIGABLE_FILES_YAML} \"\n", + " f\"based on a minimum of {w_ions_range.value} peptides.\")\n", "idx_selected = MS_spectra.loc[mask].index\n", "MS_spectra.loc[idx_selected]" ] @@ -258,7 +258,9 @@ "metadata": {}, "outputs": [], "source": [ - "w_date_range = widgets.SelectionRangeSlider(options=df_meta_rawfiles[date_col], value=[min(df_meta_rawfiles[date_col]),max(df_meta_rawfiles[date_col]) ] )\n", + "w_date_range = widgets.SelectionRangeSlider(options=df_meta_rawfiles[date_col], value=[\n", + " min(df_meta_rawfiles[date_col]), max(df_meta_rawfiles[date_col])])\n", + "\n", "\n", "def show(range):\n", " mask = df_meta_rawfiles[date_col].between(*range)\n", @@ -315,11 +317,11 @@ "outputs": [], "source": [ "_max = MS_spectra[col_summary.peptides_identified].max() + 10_001\n", - "fig, ax = plt.subplots(figsize=(10,10))\n", + "fig, ax = plt.subplots(figsize=(10, 10))\n", "_ = MS_spectra[col_summary.peptides_identified].hist(\n", - " bins=range(0,_max, 10_000),\n", + " bins=range(0, _max, 10_000),\n", " legend=True,\n", - " ax = ax)\n", + " ax=ax)\n", "fig.suptitle('Number of samples, binned in 10K steps.')\n", "fig.tight_layout()" ] @@ -330,7 +332,8 @@ "metadata": {}, "outputs": [], "source": [ - "MS_spectra[col_summary.peptides_identified].mean(), MS_spectra[col_summary.peptides_identified].std() # including folders with 0 identified peptides" + "# including folders with 0 identified peptides\n", + "MS_spectra[col_summary.peptides_identified].mean(), MS_spectra[col_summary.peptides_identified].std()" ] }, { @@ -348,7 +351,8 @@ "\n", "\n", "# calc_cutoff()\n", - "display(widgets.interactive(calc_cutoff, threshold=widgets.IntSlider(value=10000.0, min=.0, max=MS_spectra[col_summary.peptides_identified].max())))" + "display(widgets.interactive(calc_cutoff, threshold=widgets.IntSlider(\n", + " value=10000.0, min=.0, max=MS_spectra[col_summary.peptides_identified].max())))" ] }, { @@ -357,23 +361,32 @@ "metadata": {}, "outputs": [], "source": [ - "fig, axes = plt.subplots(2,2, figsize=(20,20), sharex=True)\n", + "fig, axes = plt.subplots(2, 2, figsize=(20, 20), sharex=True)\n", "\n", - "ylim_hist = (0,600)\n", + "ylim_hist = (0, 600)\n", "xlim_dens = (0, 70_000)\n", "\n", - "ax = axes[0,0]\n", - "ax = mq_all_summaries.df[col_summary.peptides_identified].plot(kind='hist', bins=50, title=\"Histogram including samples with zero identified peptides\", grid=True, ax=ax, ylim=ylim_hist)\n", - "ax = axes[1,0]\n", - "_ = mq_all_summaries.df[col_summary.peptides_identified].astype(float).plot.kde(ax=ax, title=\"Density plot including samples with zero identified peptides.\", xlim=xlim_dens)\n", + "ax = axes[0, 0]\n", + "ax = mq_all_summaries.df[col_summary.peptides_identified].plot(\n", + " kind='hist', bins=50, title=\"Histogram including samples with zero identified peptides\", grid=True, ax=ax, ylim=ylim_hist)\n", + "ax = axes[1, 0]\n", + "_ = mq_all_summaries.df[col_summary.peptides_identified].astype(float).plot.kde(\n", + " ax=ax, title=\"Density plot including samples with zero identified peptides.\", xlim=xlim_dens)\n", "\n", "threshold_m2_identified = 15_000\n", "mask = mq_all_summaries.df[col_summary.peptides_identified] >= threshold_m2_identified\n", "\n", - "ax = axes[0,1]\n", - "ax = mq_all_summaries.df.loc[mask, col_summary.peptides_identified].plot(kind='hist', bins=40, title=f\"Histogram including samples with {threshold_m2_identified:,d} and more identified peptides\", grid=True, ax=ax, ylim=ylim_hist)\n", - "ax = axes[1,1]\n", - "_ = mq_all_summaries.df.loc[mask, col_summary.peptides_identified].astype(float).plot.kde(ax=ax, title=f\"Density plot including samples with {threshold_m2_identified:,d} and more identified peptides.\", xlim=xlim_dens)\n", + "ax = axes[0, 1]\n", + "ax = mq_all_summaries.df.loc[mask,\n", + " col_summary.peptides_identified].plot(kind='hist',\n", + " bins=40,\n", + " title=f\"Histogram including samples with {threshold_m2_identified:,d} and more identified peptides\",\n", + " grid=True,\n", + " ax=ax,\n", + " ylim=ylim_hist)\n", + "ax = axes[1, 1]\n", + "_ = mq_all_summaries.df.loc[mask, col_summary.peptides_identified].astype(float).plot.kde(\n", + " ax=ax, title=f\"Density plot including samples with {threshold_m2_identified:,d} and more identified peptides.\", xlim=xlim_dens)\n", "\n", "plotting._savefig(fig, name='distribution_peptides_in_samples', folder=config.FIGUREFOLDER)" ] diff --git a/project/erda_01_mq_select_runs.py b/project/erda_01_mq_select_runs.py index 070de215e..6ae571352 100644 --- a/project/erda_01_mq_select_runs.py +++ b/project/erda_01_mq_select_runs.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 (ipykernel) # language: python @@ -24,11 +24,22 @@ # There is are many files more, where several files seem to be available in several times in different formats. # %% -import sys import logging from pathlib import Path, PurePosixPath import yaml -import random + +import ipywidgets as widgets +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt + +from vaep.io.data_objects import MqAllSummaries +from vaep import plotting +from vaep.io.mq import MaxQuantOutputDynamic + +import config +from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED + ################## ### Logging ###### @@ -41,42 +52,30 @@ logging.info('Start with handlers: \n' + "\n".join(f"- {repr(log_)}" for log_ in logger.handlers)) -### Other imports +# Other imports -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd -import ipywidgets as widgets - -from vaep.io.mq import MaxQuantOutputDynamic -from vaep import plotting - -from vaep.io import data_objects -from vaep.io.data_objects import MqAllSummaries ################## ##### CONFIG ##### ################## -import config -from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml') MAP_FOLDER_PATH = Path('config/file_paths') FPATH_ALL_SUMMARIES = FOLDER_PROCESSED / 'all_summaries.json' FN_RAWFILE_METADATA = 'data/rawfile_metadata.csv' -from config import FOLDER_DATA # project folder for storing the data logger.info(f"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}") # %% Collapsed="false" -folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir() and not folder.name.startswith('.')] +folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir() + and not folder.name.startswith('.')] # %% Collapsed="false" folders_dict = {folder.name: folder for folder in sorted(folders)} assert len(folders_dict) == len(folders), "Non unique file names" with open(MAP_FOLDER_PATH, 'w') as f: - yaml.dump({ k: str(PurePosixPath(v)) for k, v in folders_dict.items()} , f) + yaml.dump({k: str(PurePosixPath(v)) for k, v in folders_dict.items()}, f) logger.info(f"Save map of file names to file paths to: {str(MAP_FOLDER_PATH)}") # w_file = widgets.Dropdown(options=[folder for folder in folders], description='View files') @@ -126,26 +125,27 @@ # %% class col_summary: MS1 = 'MS' - MS2 = 'MS/MS' - MS2_identified = 'MS/MS Identified' - peptides_identified = 'Peptide Sequences Identified' # 'peptides.txt' should have this number of peptides + MS2 = 'MS/MS' + MS2_identified = 'MS/MS Identified' + peptides_identified = 'Peptide Sequences Identified' # 'peptides.txt' should have this number of peptides + df = mq_all_summaries.df if df is not None: MS_spectra = df[[col_summary.MS1, col_summary.MS2, col_summary.MS2_identified, col_summary.peptides_identified]] def compute_summary(threshold_identified): - mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified + mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified display(MS_spectra.loc[mask].describe(np.linspace(0.05, 0.95, 10))) - + w_ions_range = widgets.IntSlider(value=15_000, min=.0, max=MS_spectra[col_summary.peptides_identified].max()) display(widgets.interactive(compute_summary, threshold_identified=w_ions_range)) # %% -mask = MS_spectra[col_summary.peptides_identified] >= w_ions_range.value +mask = MS_spectra[col_summary.peptides_identified] >= w_ions_range.value logger.warning(f"Save {mask.sum()} file names to configuration file of selected samples: " -f"{ELIGABLE_FILES_YAML} " -f"based on a minimum of {w_ions_range.value} peptides.") + f"{ELIGABLE_FILES_YAML} " + f"based on a minimum of {w_ions_range.value} peptides.") idx_selected = MS_spectra.loc[mask].index MS_spectra.loc[idx_selected] @@ -163,7 +163,9 @@ def compute_summary(threshold_identified): df_meta_rawfiles.sort_values(date_col, inplace=True) # %% -w_date_range = widgets.SelectionRangeSlider(options=df_meta_rawfiles[date_col], value=[min(df_meta_rawfiles[date_col]),max(df_meta_rawfiles[date_col]) ] ) +w_date_range = widgets.SelectionRangeSlider(options=df_meta_rawfiles[date_col], value=[ + min(df_meta_rawfiles[date_col]), max(df_meta_rawfiles[date_col])]) + def show(range): mask = df_meta_rawfiles[date_col].between(*range) @@ -194,16 +196,17 @@ def show(range): # %% _max = MS_spectra[col_summary.peptides_identified].max() + 10_001 -fig, ax = plt.subplots(figsize=(10,10)) +fig, ax = plt.subplots(figsize=(10, 10)) _ = MS_spectra[col_summary.peptides_identified].hist( - bins=range(0,_max, 10_000), + bins=range(0, _max, 10_000), legend=True, - ax = ax) + ax=ax) fig.suptitle('Number of samples, binned in 10K steps.') fig.tight_layout() # %% -MS_spectra[col_summary.peptides_identified].mean(), MS_spectra[col_summary.peptides_identified].std() # including folders with 0 identified peptides +# including folders with 0 identified peptides +MS_spectra[col_summary.peptides_identified].mean(), MS_spectra[col_summary.peptides_identified].std() # %% @@ -216,25 +219,35 @@ def calc_cutoff(threshold=1): # calc_cutoff() -display(widgets.interactive(calc_cutoff, threshold=widgets.IntSlider(value=10000.0, min=.0, max=MS_spectra[col_summary.peptides_identified].max()))) +display(widgets.interactive(calc_cutoff, threshold=widgets.IntSlider( + value=10000.0, min=.0, max=MS_spectra[col_summary.peptides_identified].max()))) # %% -fig, axes = plt.subplots(2,2, figsize=(20,20), sharex=True) +fig, axes = plt.subplots(2, 2, figsize=(20, 20), sharex=True) -ylim_hist = (0,600) +ylim_hist = (0, 600) xlim_dens = (0, 70_000) -ax = axes[0,0] -ax = mq_all_summaries.df[col_summary.peptides_identified].plot(kind='hist', bins=50, title="Histogram including samples with zero identified peptides", grid=True, ax=ax, ylim=ylim_hist) -ax = axes[1,0] -_ = mq_all_summaries.df[col_summary.peptides_identified].astype(float).plot.kde(ax=ax, title="Density plot including samples with zero identified peptides.", xlim=xlim_dens) +ax = axes[0, 0] +ax = mq_all_summaries.df[col_summary.peptides_identified].plot( + kind='hist', bins=50, title="Histogram including samples with zero identified peptides", grid=True, ax=ax, ylim=ylim_hist) +ax = axes[1, 0] +_ = mq_all_summaries.df[col_summary.peptides_identified].astype(float).plot.kde( + ax=ax, title="Density plot including samples with zero identified peptides.", xlim=xlim_dens) threshold_m2_identified = 15_000 mask = mq_all_summaries.df[col_summary.peptides_identified] >= threshold_m2_identified -ax = axes[0,1] -ax = mq_all_summaries.df.loc[mask, col_summary.peptides_identified].plot(kind='hist', bins=40, title=f"Histogram including samples with {threshold_m2_identified:,d} and more identified peptides", grid=True, ax=ax, ylim=ylim_hist) -ax = axes[1,1] -_ = mq_all_summaries.df.loc[mask, col_summary.peptides_identified].astype(float).plot.kde(ax=ax, title=f"Density plot including samples with {threshold_m2_identified:,d} and more identified peptides.", xlim=xlim_dens) +ax = axes[0, 1] +ax = mq_all_summaries.df.loc[mask, + col_summary.peptides_identified].plot(kind='hist', + bins=40, + title=f"Histogram including samples with {threshold_m2_identified:,d} and more identified peptides", + grid=True, + ax=ax, + ylim=ylim_hist) +ax = axes[1, 1] +_ = mq_all_summaries.df.loc[mask, col_summary.peptides_identified].astype(float).plot.kde( + ax=ax, title=f"Density plot including samples with {threshold_m2_identified:,d} and more identified peptides.", xlim=xlim_dens) plotting._savefig(fig, name='distribution_peptides_in_samples', folder=config.FIGUREFOLDER) diff --git a/project/erda_02_mq_count_features.ipynb b/project/erda_02_mq_count_features.ipynb index 1d50f1f7d..2dd052693 100644 --- a/project/erda_02_mq_count_features.ipynb +++ b/project/erda_02_mq_count_features.ipynb @@ -15,33 +15,27 @@ }, "outputs": [], "source": [ + "from collections import Counter\n", "import os\n", - "import sys\n", "import logging\n", "from pathlib import Path\n", "import random\n", "import yaml\n", - "import json\n", "\n", "import pandas as pd\n", - "import ipywidgets as widgets\n", - "\n", - "### Logging setup ######\n", - "from vaep.logging import setup_nb_logger\n", - "setup_nb_logger()\n", "\n", - "### vaep imports ######\n", - "from vaep.io.mq import MaxQuantOutputDynamic\n", - "from vaep.io.data_objects import MqAllSummaries\n", - "from vaep.io.data_objects import PeptideCounter\n", "import vaep.pandas\n", + "from vaep.io.data_objects import PeptideCounter\n", + "from vaep.io.mq import MaxQuantOutputDynamic\n", "\n", - "##################\n", "##### CONFIG #####\n", - "##################\n", "from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED\n", + "from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES\n", + "\n", + "### Logging setup ######\n", + "from vaep.logging import setup_nb_logger\n", + "setup_nb_logger()\n", "\n", - "from config import FOLDER_DATA # project folder for storing the data\n", "logging.info(f\"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}\")" ] }, @@ -82,7 +76,7 @@ }, "outputs": [], "source": [ - "fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id\n", + "fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id\n", "df_ids = pd.read_csv(fn_id_old_new)\n", "df_ids" ] @@ -98,14 +92,15 @@ "cell_type": "code", "execution_count": null, "metadata": { + "lines_to_next_cell": 2, "tags": [] }, "outputs": [], "source": [ - "folders_dict = { sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids['Sample ID']}\n", + "folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids['Sample ID']}\n", "# folders_dict = {p.stem : p.parent / p.stem for p in folders_dict}\n", "# folders_dict\n", - "folders = [Path(folder_path) for folder_path in folders_dict.values()]\n" + "folders = [Path(folder_path) for folder_path in folders_dict.values()]" ] }, { @@ -119,7 +114,6 @@ "OVERWRITE = False\n", "OVERWRITE = True\n", "\n", - "from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES\n", "\n", "FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES" ] @@ -139,7 +133,6 @@ }, "outputs": [], "source": [ - "import random\n", "pd.set_option('display.max_columns', 60)\n", "random_folder, random_path = random.sample(folders_dict.items(), 1)[0]\n", "mq_output = MaxQuantOutputDynamic(random_path)\n", @@ -156,7 +149,7 @@ "outputs": [], "source": [ "use_columns = mq_output.peptides.columns[33:45]\n", - "df = mq_output.peptides[use_columns].convert_dtypes() #.to_json('test.json')\n", + "df = mq_output.peptides[use_columns].convert_dtypes() # .to_json('test.json')\n", "df" ] }, @@ -203,7 +196,7 @@ }, "outputs": [], "source": [ - "mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands" + "mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands" ] }, { @@ -294,7 +287,7 @@ "metadata": {}, "outputs": [], "source": [ - "c.most_common(10) # peptide_counter.counter.most_common(10)" + "c.most_common(10) # peptide_counter.counter.most_common(10)" ] }, { @@ -309,15 +302,15 @@ "N = 1000\n", "with open(FOLDER_PROCESSED / f'most_common_{10}_peptides.py', 'w') as f:\n", " f.write('import pandas as pd\\n\\n')\n", - " \n", - " #pprint.pformat list -> do this using standardlibrary\n", + "\n", + " # pprint.pformat list -> do this using standardlibrary\n", " # https://docs.python.org/3/library/pprint.html\n", " f.write(f\"most_common = [\\n \")\n", " f.write(',\\n '.join(f\"{str(t)}\" for t in c.most_common(N)))\n", " f.write(\"\\n]\\n\\n\")\n", - " \n", - " #peptide_counter.loaded()\n", - " \n", + "\n", + " # peptide_counter.loaded()\n", + "\n", " f.write(\"pd.DataFrame.from_records(most_common, index='Sequence', columns=['Sequence', 'counts'])\\n\")" ] }, @@ -339,7 +332,7 @@ "outputs": [], "source": [ "evidence_cols = vaep.pandas.get_columns_accessor(mq_output.evidence.reset_index())\n", - "evidence_cols # vaep.mq get this list" + "evidence_cols # vaep.mq get this list" ] }, { @@ -394,7 +387,7 @@ "metadata": {}, "outputs": [], "source": [ - "mask = evidence[evidence_cols.Intensity].isna()\n", + "mask = evidence[evidence_cols.Intensity].isna()\n", "evidence.loc[mask, evidence_cols.Type].value_counts()" ] }, @@ -405,7 +398,12 @@ "outputs": [], "source": [ "evidence_cols = vaep.io.data_objects.evidence_cols\n", - "use_cols = [evidence_cols.mz, evidence_cols.Protein_group_IDs, evidence_cols.Intensity, evidence_cols.Score, evidence_cols.Potential_contaminant]\n", + "use_cols = [\n", + " evidence_cols.mz,\n", + " evidence_cols.Protein_group_IDs,\n", + " evidence_cols.Intensity,\n", + " evidence_cols.Score,\n", + " evidence_cols.Potential_contaminant]\n", "\n", "evidence_selected = vaep.io.data_objects.select_evidence(evidence[use_cols])\n", "evidence_selected" @@ -427,7 +425,9 @@ "metadata": {}, "outputs": [], "source": [ - "evidence_selected = vaep.pandas.select_max_by(evidence_selected.reset_index(), [evidence_cols.Sequence, evidence_cols.Charge], evidence_cols.Score)\n", + "evidence_selected = vaep.pandas.select_max_by(\n", + " evidence_selected.reset_index(), [\n", + " evidence_cols.Sequence, evidence_cols.Charge], evidence_cols.Score)\n", "evidence_selected" ] }, @@ -437,7 +437,6 @@ "metadata": {}, "outputs": [], "source": [ - "from collections import Counter\n", "c = Counter()\n", "c.update(evidence.index)\n", "c.most_common(10)" @@ -516,7 +515,7 @@ "\n", "- protein groups between files\n", " - aggregate by GENE ?\n", - " - " + " -" ] }, { @@ -545,21 +544,22 @@ "outputs": [], "source": [ "use_cols = [\n", - "# pg_cols.Protein_IDs,\n", - " pg_cols.Majority_protein_IDs,\n", - " pg_cols.Gene_names,\n", - " pg_cols.Evidence_IDs,\n", - " pg_cols.Q_value,\n", - " pg_cols.Score,\n", - " pg_cols.Only_identified_by_site,\n", - " pg_cols.Reverse,\n", - " pg_cols.Potential_contaminant,\n", - " pg_cols.Intensity,\n", + " # pg_cols.Protein_IDs,\n", + " pg_cols.Majority_protein_IDs,\n", + " pg_cols.Gene_names,\n", + " pg_cols.Evidence_IDs,\n", + " pg_cols.Q_value,\n", + " pg_cols.Score,\n", + " pg_cols.Only_identified_by_site,\n", + " pg_cols.Reverse,\n", + " pg_cols.Potential_contaminant,\n", + " pg_cols.Intensity,\n", "]\n", "\n", "pd.options.display.max_rows = 100\n", "pd.options.display.min_rows = 40\n", - "mask = mq_output.proteinGroups[[pg_cols.Only_identified_by_site, pg_cols.Reverse, pg_cols.Potential_contaminant]].notna().sum(axis=1) > 0\n", + "mask = mq_output.proteinGroups[[pg_cols.Only_identified_by_site,\n", + " pg_cols.Reverse, pg_cols.Potential_contaminant]].notna().sum(axis=1) > 0\n", "mq_output.proteinGroups.loc[mask, use_cols]" ] }, @@ -571,7 +571,7 @@ "source": [ "msg = \"Omitting the data drops {0:.3f} % of the data.\"\n", "print(msg.format(\n", - "mask.sum() / len(mask) * 100\n", + " mask.sum() / len(mask) * 100\n", "))" ] }, @@ -582,7 +582,7 @@ "outputs": [], "source": [ "selection = mq_output.proteinGroups.loc[~mask, use_cols]\n", - "gene_counts = selection[pg_cols.Gene_names].value_counts() # Gene Names not unique\n", + "gene_counts = selection[pg_cols.Gene_names].value_counts() # Gene Names not unique\n", "msg = 'proportion of entries with non-unique genes: {:.3f}'\n", "print(msg.format(gene_counts.loc[gene_counts > 1].sum() / gene_counts.sum()))\n", "gene_counts.head(20)" @@ -594,7 +594,7 @@ "metadata": {}, "outputs": [], "source": [ - "mask = selection.Intensity > 0 \n", + "mask = selection.Intensity > 0\n", "msg = \"Proportion of non-zero Intensities: {:.3f} (zero_ count = {})\"\n", "print(msg.format(mask.sum() / len(mask), (~mask).sum()))\n", "selection.loc[~mask]" @@ -616,7 +616,7 @@ "Some Proteins have no gene annotation\n", " - P56181 -> mitochondrial\n", "\n", - "In the online version of Uniprot these seems to be annotated (brief check). \n", + "In the online version of Uniprot these seems to be annotated (brief check).\n", "So latest version probably has a gene annotation, so therefore these files are kept" ] }, @@ -629,7 +629,7 @@ "gene_set = selection[pg_cols.Gene_names].str.split(';')\n", "\n", "col_loc_gene_names = selection.columns.get_loc(pg_cols.Gene_names)\n", - "_ = selection.insert(col_loc_gene_names+1, 'Number of Genes', gene_set.apply(vaep.pandas.length))\n", + "_ = selection.insert(col_loc_gene_names + 1, 'Number of Genes', gene_set.apply(vaep.pandas.length))\n", "\n", "mask = gene_set.isna()\n", "selection.loc[mask]" @@ -651,7 +651,7 @@ "metadata": {}, "source": [ "Most `proteinGroups` have single genes assigned to them. If one only looks at gene sets,\n", - "one can increase uniquely identified `proteinGroups` further. \n", + "one can increase uniquely identified `proteinGroups` further.\n", "\n", "> Can `geneGroups` (sets of `Gene Names`) be used instead of `proteinGroups`?" ] @@ -722,7 +722,8 @@ "metadata": {}, "outputs": [], "source": [ - "selection = vaep.pandas.select_max_by(df=selection.loc[~mask_no_gene].reset_index(), grouping_columns=[pg_cols.Gene_names], selection_column=pg_cols.Score)\n", + "selection = vaep.pandas.select_max_by(df=selection.loc[~mask_no_gene].reset_index(), grouping_columns=[\n", + " pg_cols.Gene_names], selection_column=pg_cols.Score)\n", "logging.info(f\"Selection shape after dropping duplicates by gene: {selection.shape}\")\n", "selection = selection.set_index(pg_cols.Protein_IDs)\n", "mask = selection[cols.Gene_names].isin(non_unique_genes)\n", @@ -756,7 +757,7 @@ "metadata": {}, "outputs": [], "source": [ - "vaep.pandas.counts_with_proportion(pd.Series(c)) # Most proteinGroups are unique" + "vaep.pandas.counts_with_proportion(pd.Series(c)) # Most proteinGroups are unique" ] }, { @@ -766,7 +767,7 @@ "### Count genes\n", "Genes sets could be used to identify common features.\n", "\n", - "> The assignment of isoforms to one proteinGroup or another might be volatile. \n", + "> The assignment of isoforms to one proteinGroup or another might be volatile.\n", "> A single (unique) peptide could lead to different assignments.\n", "> Imputation on the evidence level could be a way to alleviate this problem\n", "\n", @@ -782,14 +783,14 @@ "gene_counter = vaep.io.data_objects.GeneCounter(FNAME_C_GENES, overwrite=OVERWRITE)\n", "\n", "if not gene_counter.dumps:\n", - " #empty dict, replace\n", - " gene_counter.dumps = dict(protein_groups_counter.dumps) # prot proteinGroups files to GeneCounter\n", + " # empty dict, replace\n", + " gene_counter.dumps = dict(protein_groups_counter.dumps) # prot proteinGroups files to GeneCounter\n", "pg_dumps = list(gene_counter.dumps.values())\n", "\n", "c_genes = gene_counter.sum_over_files(folders=pg_dumps)\n", "\n", "c_genes = pd.Series(c_genes)\n", - "vaep.pandas.counts_with_proportion(c_genes) # Most proteinGroups are unique" + "vaep.pandas.counts_with_proportion(c_genes) # Most proteinGroups are unique" ] }, { diff --git a/project/erda_02_mq_count_features.py b/project/erda_02_mq_count_features.py index 80821096b..a92c3a098 100644 --- a/project/erda_02_mq_count_features.py +++ b/project/erda_02_mq_count_features.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.15.1 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 (ipykernel) # language: python @@ -16,33 +16,27 @@ # # Count peptides over all files # %% +from collections import Counter import os -import sys import logging from pathlib import Path import random import yaml -import json import pandas as pd -import ipywidgets as widgets - -### Logging setup ###### -from vaep.logging import setup_nb_logger -setup_nb_logger() -### vaep imports ###### -from vaep.io.mq import MaxQuantOutputDynamic -from vaep.io.data_objects import MqAllSummaries -from vaep.io.data_objects import PeptideCounter import vaep.pandas +from vaep.io.data_objects import PeptideCounter +from vaep.io.mq import MaxQuantOutputDynamic -################## ##### CONFIG ##### -################## from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED +from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES + +### Logging setup ###### +from vaep.logging import setup_nb_logger +setup_nb_logger() -from config import FOLDER_DATA # project folder for storing the data logging.info(f"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}") # %% [markdown] @@ -63,7 +57,7 @@ assert len(files) == len(folders_dict) == len(folders) # %% -fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id +fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id df_ids = pd.read_csv(fn_id_old_new) df_ids @@ -71,7 +65,7 @@ # Select files and create list of folders # %% -folders_dict = { sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids['Sample ID']} +folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids['Sample ID']} # folders_dict = {p.stem : p.parent / p.stem for p in folders_dict} # folders_dict folders = [Path(folder_path) for folder_path in folders_dict.values()] @@ -81,7 +75,6 @@ OVERWRITE = False OVERWRITE = True -from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES @@ -89,7 +82,6 @@ # ## Random example # %% -import random pd.set_option('display.max_columns', 60) random_folder, random_path = random.sample(folders_dict.items(), 1)[0] mq_output = MaxQuantOutputDynamic(random_path) @@ -98,7 +90,7 @@ # %% use_columns = mq_output.peptides.columns[33:45] -df = mq_output.peptides[use_columns].convert_dtypes() #.to_json('test.json') +df = mq_output.peptides[use_columns].convert_dtypes() # .to_json('test.json') df # %% @@ -113,7 +105,7 @@ pd.read_json(df_json_string, orient='index') # %% -mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands +mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands # %% [markdown] # ## Count aggregated peptides @@ -150,22 +142,22 @@ new_name # %% -c.most_common(10) # peptide_counter.counter.most_common(10) +c.most_common(10) # peptide_counter.counter.most_common(10) # %% # To share as python file N = 1000 with open(FOLDER_PROCESSED / f'most_common_{10}_peptides.py', 'w') as f: f.write('import pandas as pd\n\n') - - #pprint.pformat list -> do this using standardlibrary + + # pprint.pformat list -> do this using standardlibrary # https://docs.python.org/3/library/pprint.html f.write(f"most_common = [\n ") f.write(',\n '.join(f"{str(t)}" for t in c.most_common(N))) f.write("\n]\n\n") - - #peptide_counter.loaded() - + + # peptide_counter.loaded() + f.write("pd.DataFrame.from_records(most_common, index='Sequence', columns=['Sequence', 'counts'])\n") # %% [markdown] Collapsed="false" @@ -175,7 +167,7 @@ # %% evidence_cols = vaep.pandas.get_columns_accessor(mq_output.evidence.reset_index()) -evidence_cols # vaep.mq get this list +evidence_cols # vaep.mq get this list # %% evidence = mq_output.evidence.set_index(evidence_cols.Charge, append=True) @@ -198,12 +190,17 @@ # These are apparently peptides identified by an MS2 spectrum but which could not be quantified by a MS1 scans # %% -mask = evidence[evidence_cols.Intensity].isna() +mask = evidence[evidence_cols.Intensity].isna() evidence.loc[mask, evidence_cols.Type].value_counts() # %% evidence_cols = vaep.io.data_objects.evidence_cols -use_cols = [evidence_cols.mz, evidence_cols.Protein_group_IDs, evidence_cols.Intensity, evidence_cols.Score, evidence_cols.Potential_contaminant] +use_cols = [ + evidence_cols.mz, + evidence_cols.Protein_group_IDs, + evidence_cols.Intensity, + evidence_cols.Score, + evidence_cols.Potential_contaminant] evidence_selected = vaep.io.data_objects.select_evidence(evidence[use_cols]) evidence_selected @@ -213,11 +210,12 @@ evidence_selected # %% -evidence_selected = vaep.pandas.select_max_by(evidence_selected.reset_index(), [evidence_cols.Sequence, evidence_cols.Charge], evidence_cols.Score) +evidence_selected = vaep.pandas.select_max_by( + evidence_selected.reset_index(), [ + evidence_cols.Sequence, evidence_cols.Charge], evidence_cols.Score) evidence_selected # %% -from collections import Counter c = Counter() c.update(evidence.index) c.most_common(10) @@ -254,7 +252,7 @@ # # - protein groups between files # - aggregate by GENE ? -# - +# - # %% mq_output.proteinGroups.describe(include='all') @@ -265,38 +263,39 @@ # %% use_cols = [ -# pg_cols.Protein_IDs, - pg_cols.Majority_protein_IDs, - pg_cols.Gene_names, - pg_cols.Evidence_IDs, - pg_cols.Q_value, - pg_cols.Score, - pg_cols.Only_identified_by_site, - pg_cols.Reverse, - pg_cols.Potential_contaminant, - pg_cols.Intensity, + # pg_cols.Protein_IDs, + pg_cols.Majority_protein_IDs, + pg_cols.Gene_names, + pg_cols.Evidence_IDs, + pg_cols.Q_value, + pg_cols.Score, + pg_cols.Only_identified_by_site, + pg_cols.Reverse, + pg_cols.Potential_contaminant, + pg_cols.Intensity, ] pd.options.display.max_rows = 100 pd.options.display.min_rows = 40 -mask = mq_output.proteinGroups[[pg_cols.Only_identified_by_site, pg_cols.Reverse, pg_cols.Potential_contaminant]].notna().sum(axis=1) > 0 +mask = mq_output.proteinGroups[[pg_cols.Only_identified_by_site, + pg_cols.Reverse, pg_cols.Potential_contaminant]].notna().sum(axis=1) > 0 mq_output.proteinGroups.loc[mask, use_cols] # %% msg = "Omitting the data drops {0:.3f} % of the data." print(msg.format( -mask.sum() / len(mask) * 100 + mask.sum() / len(mask) * 100 )) # %% selection = mq_output.proteinGroups.loc[~mask, use_cols] -gene_counts = selection[pg_cols.Gene_names].value_counts() # Gene Names not unique +gene_counts = selection[pg_cols.Gene_names].value_counts() # Gene Names not unique msg = 'proportion of entries with non-unique genes: {:.3f}' print(msg.format(gene_counts.loc[gene_counts > 1].sum() / gene_counts.sum())) gene_counts.head(20) # %% -mask = selection.Intensity > 0 +mask = selection.Intensity > 0 msg = "Proportion of non-zero Intensities: {:.3f} (zero_ count = {})" print(msg.format(mask.sum() / len(mask), (~mask).sum())) selection.loc[~mask] @@ -308,14 +307,14 @@ # Some Proteins have no gene annotation # - P56181 -> mitochondrial # -# In the online version of Uniprot these seems to be annotated (brief check). +# In the online version of Uniprot these seems to be annotated (brief check). # So latest version probably has a gene annotation, so therefore these files are kept # %% gene_set = selection[pg_cols.Gene_names].str.split(';') col_loc_gene_names = selection.columns.get_loc(pg_cols.Gene_names) -_ = selection.insert(col_loc_gene_names+1, 'Number of Genes', gene_set.apply(vaep.pandas.length)) +_ = selection.insert(col_loc_gene_names + 1, 'Number of Genes', gene_set.apply(vaep.pandas.length)) mask = gene_set.isna() selection.loc[mask] @@ -327,7 +326,7 @@ # %% [markdown] # Most `proteinGroups` have single genes assigned to them. If one only looks at gene sets, -# one can increase uniquely identified `proteinGroups` further. +# one can increase uniquely identified `proteinGroups` further. # # > Can `geneGroups` (sets of `Gene Names`) be used instead of `proteinGroups`? @@ -360,7 +359,8 @@ selection_no_gene # %% -selection = vaep.pandas.select_max_by(df=selection.loc[~mask_no_gene].reset_index(), grouping_columns=[pg_cols.Gene_names], selection_column=pg_cols.Score) +selection = vaep.pandas.select_max_by(df=selection.loc[~mask_no_gene].reset_index(), grouping_columns=[ + pg_cols.Gene_names], selection_column=pg_cols.Score) logging.info(f"Selection shape after dropping duplicates by gene: {selection.shape}") selection = selection.set_index(pg_cols.Protein_IDs) mask = selection[cols.Gene_names].isin(non_unique_genes) @@ -374,13 +374,13 @@ c = protein_groups_counter.sum_over_files(folders=folders) # %% -vaep.pandas.counts_with_proportion(pd.Series(c)) # Most proteinGroups are unique +vaep.pandas.counts_with_proportion(pd.Series(c)) # Most proteinGroups are unique # %% [markdown] # ### Count genes # Genes sets could be used to identify common features. # -# > The assignment of isoforms to one proteinGroup or another might be volatile. +# > The assignment of isoforms to one proteinGroup or another might be volatile. # > A single (unique) peptide could lead to different assignments. # > Imputation on the evidence level could be a way to alleviate this problem # @@ -390,14 +390,14 @@ gene_counter = vaep.io.data_objects.GeneCounter(FNAME_C_GENES, overwrite=OVERWRITE) if not gene_counter.dumps: - #empty dict, replace - gene_counter.dumps = dict(protein_groups_counter.dumps) # prot proteinGroups files to GeneCounter + # empty dict, replace + gene_counter.dumps = dict(protein_groups_counter.dumps) # prot proteinGroups files to GeneCounter pg_dumps = list(gene_counter.dumps.values()) c_genes = gene_counter.sum_over_files(folders=pg_dumps) c_genes = pd.Series(c_genes) -vaep.pandas.counts_with_proportion(c_genes) # Most proteinGroups are unique +vaep.pandas.counts_with_proportion(c_genes) # Most proteinGroups are unique # %% [markdown] Collapsed="false" # ## Theoretial Peptides from used fasta-file diff --git a/project/erda_03_training_data.ipynb b/project/erda_03_training_data.ipynb index 269f55bc7..1047d6ec9 100644 --- a/project/erda_03_training_data.ipynb +++ b/project/erda_03_training_data.ipynb @@ -32,15 +32,10 @@ "\n", "import vaep\n", "\n", - "import config" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ + "import config\n", + "from config.training_data import peptides as cfg\n", + "\n", + "\n", "def join_as_str(seq):\n", " ret = \"_\".join(str(x) for x in seq)\n", " return ret" @@ -63,10 +58,10 @@ "outputs": [], "source": [ "RANDOM_SEED: int = 42 # Random seed for reproducibility\n", - "FEAT_COMPLETNESS_CUTOFF = 0.25 # Minimal proportion of samples which have to share a feature\n", + "FEAT_COMPLETNESS_CUTOFF = 0.25 # Minimal proportion of samples which have to share a feature\n", "SAMPLE_COL = 'Sample ID'\n", "OUT_FOLDER = 'data/selected/'\n", - "FN_ID_OLD_NEW: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id" + "FN_ID_OLD_NEW: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id" ] }, { @@ -85,7 +80,6 @@ "outputs": [], "source": [ "# options = ['peptides', 'evidence', 'proteinGroups']\n", - "from config.training_data import peptides as cfg\n", "# from config.training_data import evidence as cfg\n", "# from config.training_data import proteinGroups as cfg\n", "\n", @@ -178,7 +172,7 @@ "outputs": [], "source": [ "if TYPES_COUNT:\n", - " counts = counts.convert_dtypes().astype({'Charge': int}) #\n", + " counts = counts.convert_dtypes().astype({'Charge': int})\n", "mask = counts['proportion'] >= FEAT_COMPLETNESS_CUTOFF\n", "counts.loc[mask]" ] @@ -250,14 +244,16 @@ "source": [ "def load_fct(path):\n", " s = (\n", - " pd.read_csv(path, index_col=cfg.IDX_COLS_LONG[1:], usecols=[*cfg.IDX_COLS_LONG[1:], \"Intensity\"])\n", - " .squeeze()\n", - " .astype(pd.Int64Dtype())\n", + " pd.read_csv(path, index_col=cfg.IDX_COLS_LONG[1:], usecols=[*cfg.IDX_COLS_LONG[1:], \"Intensity\"])\n", + " .squeeze()\n", + " .astype(pd.Int64Dtype())\n", " )\n", " if len(cfg.IDX_COLS_LONG[1:]) > 1:\n", " s.index = s.index.map(join_as_str)\n", - " \n", + "\n", " return s\n", + "\n", + "\n", "load_fct(selected_dumps[0][-1])" ] }, @@ -288,7 +284,7 @@ " logging.warning(f\"Empty file: {path}\")\n", " failed.append((id, path))\n", " pbar.update(1)\n", - " \n", + "\n", " return all" ] }, @@ -305,7 +301,7 @@ "metadata": {}, "outputs": [], "source": [ - "all = None # free memory\n", + "all = None # free memory\n", "\n", "collect_intensities = partial(collect, index=IDX_selected, load_fct=load_fct)\n", "\n", @@ -316,10 +312,10 @@ " tqdm_notebook(\n", " p.imap(collect_intensities,\n", " np.array_split(selected_dumps, N_WORKERS)),\n", - " total=N_WORKERS,\n", + " total=N_WORKERS,\n", " )\n", - " ) \n", - " \n", + " )\n", + "\n", "all = pd.concat(all, axis=1)\n", "all" ] @@ -351,7 +347,7 @@ "outputs": [], "source": [ "%%time\n", - "fname = out_folder / config.insert_shape(all, 'intensities_wide_selected{}.pkl') \n", + "fname = out_folder / config.insert_shape(all, 'intensities_wide_selected{}.pkl')\n", "all.to_pickle(fname)\n", "fname" ] diff --git a/project/erda_03_training_data.py b/project/erda_03_training_data.py index 1d32f85d4..09bfdcc41 100644 --- a/project/erda_03_training_data.py +++ b/project/erda_03_training_data.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 (ipykernel) # language: python @@ -36,9 +36,9 @@ import vaep import config +from config.training_data import peptides as cfg -# %% def join_as_str(seq): ret = "_".join(str(x) for x in seq) return ret @@ -49,10 +49,10 @@ def join_as_str(seq): # %% [tag=parameters] RANDOM_SEED: int = 42 # Random seed for reproducibility -FEAT_COMPLETNESS_CUTOFF = 0.25 # Minimal proportion of samples which have to share a feature +FEAT_COMPLETNESS_CUTOFF = 0.25 # Minimal proportion of samples which have to share a feature SAMPLE_COL = 'Sample ID' OUT_FOLDER = 'data/selected/' -FN_ID_OLD_NEW: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id +FN_ID_OLD_NEW: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id # %% [markdown] @@ -60,7 +60,6 @@ def join_as_str(seq): # %% # options = ['peptides', 'evidence', 'proteinGroups'] -from config.training_data import peptides as cfg # from config.training_data import evidence as cfg # from config.training_data import proteinGroups as cfg @@ -111,7 +110,7 @@ def join_as_str(seq): # %% if TYPES_COUNT: - counts = counts.convert_dtypes().astype({'Charge': int}) # + counts = counts.convert_dtypes().astype({'Charge': int}) mask = counts['proportion'] >= FEAT_COMPLETNESS_CUTOFF counts.loc[mask] @@ -148,14 +147,16 @@ def join_as_str(seq): # %% def load_fct(path): s = ( - pd.read_csv(path, index_col=cfg.IDX_COLS_LONG[1:], usecols=[*cfg.IDX_COLS_LONG[1:], "Intensity"]) - .squeeze() - .astype(pd.Int64Dtype()) + pd.read_csv(path, index_col=cfg.IDX_COLS_LONG[1:], usecols=[*cfg.IDX_COLS_LONG[1:], "Intensity"]) + .squeeze() + .astype(pd.Int64Dtype()) ) if len(cfg.IDX_COLS_LONG[1:]) > 1: s.index = s.index.map(join_as_str) - + return s + + load_fct(selected_dumps[0][-1]) @@ -181,7 +182,7 @@ def collect(folders, index, load_fct): logging.warning(f"Empty file: {path}") failed.append((id, path)) pbar.update(1) - + return all @@ -189,7 +190,7 @@ def collect(folders, index, load_fct): # ## Collect intensities in parallel # %% -all = None # free memory +all = None # free memory collect_intensities = partial(collect, index=IDX_selected, load_fct=load_fct) @@ -200,10 +201,10 @@ def collect(folders, index, load_fct): tqdm_notebook( p.imap(collect_intensities, np.array_split(selected_dumps, N_WORKERS)), - total=N_WORKERS, + total=N_WORKERS, ) - ) - + ) + all = pd.concat(all, axis=1) all @@ -217,7 +218,7 @@ def collect(folders, index, load_fct): # %% # %%time -fname = out_folder / config.insert_shape(all, 'intensities_wide_selected{}.pkl') +fname = out_folder / config.insert_shape(all, 'intensities_wide_selected{}.pkl') all.to_pickle(fname) fname diff --git a/project/erda_04_transpose_file.ipynb b/project/erda_04_transpose_file.ipynb index 6ddcf659e..a8e1c6f1d 100644 --- a/project/erda_04_transpose_file.ipynb +++ b/project/erda_04_transpose_file.ipynb @@ -38,13 +38,13 @@ "metadata": {}, "outputs": [], "source": [ - "# out_folder = Path('data/selected/proteinGroups') \n", + "# out_folder = Path('data/selected/proteinGroups')\n", "# fname = out_folder / 'intensities_wide_selected_N04550_M07444.pkl'\n", "\n", - "# out_folder = Path('data/selected/peptides') \n", + "# out_folder = Path('data/selected/peptides')\n", "# fname = out_folder / 'intensities_wide_selected_N42881_M07441.pkl'\n", "\n", - "out_folder = Path('data/selected/evidence') \n", + "out_folder = Path('data/selected/evidence')\n", "fname = out_folder / 'intensities_wide_selected_N49560_M07444.pkl'" ] }, @@ -60,9 +60,11 @@ " stem = fname.stem.split(split)[0]\n", " return f\"{stem}{{}}{ext}\"\n", "\n", + "\n", "def memory_usage_in_mb(df):\n", " return df.memory_usage(deep=True).sum() / (2**20)\n", "\n", + "\n", "template = get_template(fname)\n", "template" ] @@ -119,7 +121,7 @@ "source": [ "# %%time\n", "# df = pd.read_csv(fname.with_suffix('.csv'), index_col=0)\n", - "# df.memory_usage(deep=True).sum() / (2**20) " + "# df.memory_usage(deep=True).sum() / (2**20)" ] }, { @@ -223,7 +225,7 @@ "outputs": [], "source": [ "%%time\n", - "fname = out_folder / config.insert_shape(df, 'absent_0_present_1_selected{}.pkl')\n", + "fname = out_folder / config.insert_shape(df, 'absent_0_present_1_selected{}.pkl')\n", "\n", "files_out[fname.name] = fname.as_posix()\n", "df.to_pickle(fname)" diff --git a/project/erda_04_transpose_file.py b/project/erda_04_transpose_file.py index c9c6db02c..e26aa156e 100644 --- a/project/erda_04_transpose_file.py +++ b/project/erda_04_transpose_file.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 (ipykernel) # language: python @@ -27,13 +27,13 @@ # Paramters # %% -# out_folder = Path('data/selected/proteinGroups') +# out_folder = Path('data/selected/proteinGroups') # fname = out_folder / 'intensities_wide_selected_N04550_M07444.pkl' -# out_folder = Path('data/selected/peptides') +# out_folder = Path('data/selected/peptides') # fname = out_folder / 'intensities_wide_selected_N42881_M07441.pkl' -out_folder = Path('data/selected/evidence') +out_folder = Path('data/selected/evidence') fname = out_folder / 'intensities_wide_selected_N49560_M07444.pkl' @@ -43,9 +43,11 @@ def get_template(fname, split='_N'): stem = fname.stem.split(split)[0] return f"{stem}{{}}{ext}" + def memory_usage_in_mb(df): return df.memory_usage(deep=True).sum() / (2**20) + template = get_template(fname) template @@ -69,7 +71,7 @@ def memory_usage_in_mb(df): # %% # # %%time # df = pd.read_csv(fname.with_suffix('.csv'), index_col=0) -# df.memory_usage(deep=True).sum() / (2**20) +# df.memory_usage(deep=True).sum() / (2**20) # %% # %%time @@ -119,7 +121,7 @@ def memory_usage_in_mb(df): # %% # %%time -fname = out_folder / config.insert_shape(df, 'absent_0_present_1_selected{}.pkl') +fname = out_folder / config.insert_shape(df, 'absent_0_present_1_selected{}.pkl') files_out[fname.name] = fname.as_posix() df.to_pickle(fname) diff --git a/project/erda_05_parse_paramter_files.ipynb b/project/erda_05_parse_paramter_files.ipynb index 60a05b72d..ba59184a3 100644 --- a/project/erda_05_parse_paramter_files.ipynb +++ b/project/erda_05_parse_paramter_files.ipynb @@ -34,6 +34,12 @@ }, "outputs": [], "source": [ + "import logging\n", + "\n", + "import xml.etree.ElementTree as ET\n", + "\n", + "logger = logging.getLogger()\n", + "\n", "test_file = 'data/mqpar_example.xml'" ] }, @@ -90,7 +96,7 @@ }, "outputs": [], "source": [ - "import xml.etree.ElementTree as ET\n", + "\n", "\n", "def add_record(data, tag, record):\n", " if tag in data:\n", diff --git a/project/erda_05_parse_paramter_files.py b/project/erda_05_parse_paramter_files.py index 7f3cb7603..eb108d4f5 100644 --- a/project/erda_05_parse_paramter_files.py +++ b/project/erda_05_parse_paramter_files.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.15.1 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 (ipykernel) # language: python diff --git a/project/erda_12_explore_raw_MQ_data.ipynb b/project/erda_12_explore_raw_MQ_data.ipynb index 03dfa8716..d2ffa8b9a 100644 --- a/project/erda_12_explore_raw_MQ_data.ipynb +++ b/project/erda_12_explore_raw_MQ_data.ipynb @@ -43,18 +43,14 @@ "import vaep.io.mq as mq\n", "from vaep.io.mq import mq_col\n", "\n", - "\n", - "from vaep.logging import setup_nb_logger\n", - "logger = setup_nb_logger()\n", - "\n", - "##################\n", "##### CONFIG #####\n", - "##################\n", - "\n", "import config\n", - "from config import FIGUREFOLDER\n", - "# from config import FOLDER_RAW_DATA\n", "from config import FOLDER_MQ_TXT_DATA as FOLDER_RAW_DATA\n", + "from config import FIGUREFOLDER\n", + "\n", + "\n", + "from vaep.logging import setup_nb_logger\n", + "logger = setup_nb_logger()\n", "\n", "\n", "print(f\"Search Raw-Files on path: {FOLDER_RAW_DATA}\")" @@ -138,7 +134,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Not all peptides are associated with a Protein or Gene by MQ, although there is evidence for the peptide. This is due to potential `CON_`taminants in the medium which is encouded by default by MQ." + "Not all peptides are associated with a Protein or Gene by MQ, although\n", + "there is evidence for the peptide. This is due to potential\n", + "`CON_`taminants in the medium which is encouded by default by MQ." ] }, { @@ -154,7 +152,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## `evidence.txt` \n", + "## `evidence.txt`\n", "\n", "contains\n", "- retention time for peptides\n", @@ -302,7 +300,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's see several quartiles for both median and standard deviation (the columns are independent from each other) for the retention time" + "Let's see several quartiles for both median and standard deviation (the\n", + "columns are independent from each other) for the retention time" ] }, { @@ -368,7 +367,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Model evaluation possibility: Discard samples with several measurements from an experiment and predict value. See which intensity measurement corresponds more closely. " + "Model evaluation possibility: Discard samples with several measurements\n", + "from an experiment and predict value. See which intensity measurement\n", + "corresponds more closely." ] }, { @@ -438,7 +439,8 @@ "## Differences in intensities b/w peptides.txt and evidence.txt\n", "\n", "\n", - "The intensity reported in `peptides.txt` corresponds to roughly to the sum of the intensities found in different scans:" + "The intensity reported in `peptides.txt` corresponds to roughly to the\n", + "sum of the intensities found in different scans:" ] }, { @@ -530,7 +532,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Several smaller and larger differences in an intensity range way below the detection limit arise for some sequences. " + "Several smaller and larger differences in an intensity range way below the detection limit arise for some sequences." ] }, { @@ -837,7 +839,7 @@ "aggregators = [\"Sequence\", \"Score\", mq_col.INTENSITY]\n", "mask_intensity_not_na = mq_output.evidence.Intensity.notna()\n", "seq_max_score_max_intensity = mq_output.evidence.loc[mask_intensity_not_na].reset_index(\n", - ")[aggregators+[\"Proteins\", \"Gene names\"]].sort_values(by=aggregators).set_index(\"Sequence\").groupby(level=0).last()\n", + ")[aggregators + [\"Proteins\", \"Gene names\"]].sort_values(by=aggregators).set_index(\"Sequence\").groupby(level=0).last()\n", "seq_max_score_max_intensity" ] }, @@ -882,8 +884,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "These might be a candiate for evaluating predictions, as the information is measured, but unknown. \n", - "If they cannot be assigned, the closest fit on different genes with model predictions could be a criterion for selection" + "These might be a candiate for evaluating predictions, as the information is measured, but unknown.\n", + "If they cannot be assigned, the closest fit on different genes with\n", + "model predictions could be a criterion for selection" ] }, { @@ -923,7 +926,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Some hundred peptides map to more than two genes " + "Some hundred peptides map to more than two genes" ] }, { @@ -955,7 +958,7 @@ "- multiple genes:\n", " - select first and add reference in others\n", " - split and dump repeatedly\n", - " \n", + "\n", "Load fasta-file information" ] }, @@ -1025,7 +1028,8 @@ "outputs": [], "source": [ "mask = mq_output.peptides[mq_col.LEADING_RAZOR_PROTEIN].isin(set_proteins_to_remove)\n", - "mq_output.peptides.loc[mask, 'Potential contaminant'].value_counts() # ToDo: Remove potential contaminants, check evidence.txt" + "# ToDo: Remove potential contaminants, check evidence.txt\n", + "mq_output.peptides.loc[mask, 'Potential contaminant'].value_counts()" ] }, { @@ -1178,8 +1182,7 @@ "\n", "Does a group of peptide only assigns unique set of genes? Genes can have more than one protein.\n", " - first build groups\n", - " - then see matches (see further below)\n", - " " + " - then see matches (see further below)\n" ] }, { @@ -1235,9 +1238,8 @@ "metadata": {}, "outputs": [], "source": [ - "_mask_con = peptides_with_single_gene.loc[mask, mq_col.PROTEINS].str.split(\";\"\n", - " ).apply(lambda x: [True if \"CON_\" in item else False for item in x]\n", - " ).apply(all)\n", + "_mask_con = peptides_with_single_gene.loc[mask, mq_col.PROTEINS].str.split(\";\").apply(\n", + " lambda x: [True if \"CON_\" in item else False for item in x]).apply(all)\n", "\n", "assert _mask_con.sum() == 0, \"There are peptides resulting only from possible confounders: {}\".format(\n", " \", \".join(str(x) for x in peptides_with_single_gene.loc[mask, mq_col.PROTEINS].loc[_mask_con].index))" @@ -1294,7 +1296,7 @@ "metadata": {}, "outputs": [], "source": [ - "gene_data[mq_col.PROTEINS].value_counts() # combine? select first in case of a CON_ as leading razor protein?" + "gene_data[mq_col.PROTEINS].value_counts() # combine? select first in case of a CON_ as leading razor protein?" ] }, { @@ -1354,7 +1356,7 @@ "peps_in_data = gene_data.index\n", "\n", "mq.calculate_completness_for_sample(\n", - " peps_exact_cleaved=peps_exact_cleaved, \n", + " peps_exact_cleaved=peps_exact_cleaved,\n", " peps_in_data=peps_in_data)" ] }, @@ -1548,7 +1550,7 @@ "metadata": {}, "outputs": [], "source": [ - "s_completeness = pd.Series(completeness_per_gene, name='completenes_by_gene')\n", + "s_completeness = pd.Series(completeness_per_gene, name='completenes_by_gene')\n", "s_completeness.describe()" ] }, @@ -1559,13 +1561,21 @@ "outputs": [], "source": [ "N_BINS = 20\n", - "ax = s_completeness.plot(kind='hist',\n", - " bins=N_BINS,\n", - " xticks=[x/100 for x in range(0, 101, 5)],\n", - " figsize=(10, 5),\n", - " rot=90,\n", - " title=f\"Frequency of proportion of observed exact peptides (completness) per razor protein from 0 to 1 in {N_BINS} bins\"\n", - " f\"\\nin sample {mq_output.folder.stem}\")\n", + "ax = s_completeness.plot(\n", + " kind='hist',\n", + " bins=N_BINS,\n", + " xticks=[\n", + " x /\n", + " 100 for x in range(\n", + " 0,\n", + " 101,\n", + " 5)],\n", + " figsize=(\n", + " 10,\n", + " 5),\n", + " rot=90,\n", + " title=f\"Frequency of proportion of observed exact peptides (completness) per razor protein from 0 to 1 in {N_BINS} bins\"\n", + " f\"\\nin sample {mq_output.folder.stem}\")\n", "\n", "_ = ax.set_xlabel(\n", " \"Proportion of exactly observed peptides (including up to 2 mis-cleavages)\")\n", diff --git a/project/erda_12_explore_raw_MQ_data.py b/project/erda_12_explore_raw_MQ_data.py index fc788ad17..13b0c6d0d 100644 --- a/project/erda_12_explore_raw_MQ_data.py +++ b/project/erda_12_explore_raw_MQ_data.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3.8.13 ('vaep') # language: python @@ -46,18 +46,14 @@ import vaep.io.mq as mq from vaep.io.mq import mq_col - -from vaep.logging import setup_nb_logger -logger = setup_nb_logger() - -################## ##### CONFIG ##### -################## - import config -from config import FIGUREFOLDER -# from config import FOLDER_RAW_DATA from config import FOLDER_MQ_TXT_DATA as FOLDER_RAW_DATA +from config import FIGUREFOLDER + + +from vaep.logging import setup_nb_logger +logger = setup_nb_logger() print(f"Search Raw-Files on path: {FOLDER_RAW_DATA}") @@ -95,13 +91,15 @@ intensities # %% [markdown] -# Not all peptides are associated with a Protein or Gene by MQ, although there is evidence for the peptide. This is due to potential `CON_`taminants in the medium which is encouded by default by MQ. +# Not all peptides are associated with a Protein or Gene by MQ, although +# there is evidence for the peptide. This is due to potential +# `CON_`taminants in the medium which is encouded by default by MQ. # %% mq_output.peptides[FASTA_KEYS].isna().sum() # %% [markdown] -# ## `evidence.txt` +# ## `evidence.txt` # # contains # - retention time for peptides @@ -170,7 +168,8 @@ rt_summary # %% [markdown] -# Let's see several quartiles for both median and standard deviation (the columns are independent from each other) for the retention time +# Let's see several quartiles for both median and standard deviation (the +# columns are independent from each other) for the retention time # %% rt_summary.describe(percentiles=[0.8, 0.9, 0.95, 0.96, 0.97, 0.98, 0.99]) @@ -196,7 +195,9 @@ mq_output.evidence.loc[mask_indices] # %% [markdown] -# Model evaluation possibility: Discard samples with several measurements from an experiment and predict value. See which intensity measurement corresponds more closely. +# Model evaluation possibility: Discard samples with several measurements +# from an experiment and predict value. See which intensity measurement +# corresponds more closely. # %% _peptide = random.choice(mask_indices) @@ -228,7 +229,8 @@ # ## Differences in intensities b/w peptides.txt and evidence.txt # # -# The intensity reported in `peptides.txt` corresponds to roughly to the sum of the intensities found in different scans: +# The intensity reported in `peptides.txt` corresponds to roughly to the +# sum of the intensities found in different scans: # %% col_intensity = mq_col.INTENSITY @@ -270,7 +272,7 @@ _diff[mask_diff].describe() # %% [markdown] -# Several smaller and larger differences in an intensity range way below the detection limit arise for some sequences. +# Several smaller and larger differences in an intensity range way below the detection limit arise for some sequences. # %% [markdown] # ### Ideas on source of difference @@ -411,7 +413,7 @@ aggregators = ["Sequence", "Score", mq_col.INTENSITY] mask_intensity_not_na = mq_output.evidence.Intensity.notna() seq_max_score_max_intensity = mq_output.evidence.loc[mask_intensity_not_na].reset_index( -)[aggregators+["Proteins", "Gene names"]].sort_values(by=aggregators).set_index("Sequence").groupby(level=0).last() +)[aggregators + ["Proteins", "Gene names"]].sort_values(by=aggregators).set_index("Sequence").groupby(level=0).last() seq_max_score_max_intensity # %% @@ -430,8 +432,9 @@ seq_max_score_max_intensity.loc[mask_seq_selected_not_assigned] # %% [markdown] -# These might be a candiate for evaluating predictions, as the information is measured, but unknown. -# If they cannot be assigned, the closest fit on different genes with model predictions could be a criterion for selection +# These might be a candiate for evaluating predictions, as the information is measured, but unknown. +# If they cannot be assigned, the closest fit on different genes with +# model predictions could be a criterion for selection # %% [markdown] # ## Create dumps of intensities in `peptides.txt` @@ -447,7 +450,7 @@ # ## Create dumps per gene # %% [markdown] -# Some hundred peptides map to more than two genes +# Some hundred peptides map to more than two genes # %% seq_max_score_max_intensity[mq_col.GENE_NAMES].str.split(";" @@ -465,7 +468,7 @@ # - multiple genes: # - select first and add reference in others # - split and dump repeatedly -# +# # Load fasta-file information # %% @@ -497,7 +500,8 @@ # %% mask = mq_output.peptides[mq_col.LEADING_RAZOR_PROTEIN].isin(set_proteins_to_remove) -mq_output.peptides.loc[mask, 'Potential contaminant'].value_counts() # ToDo: Remove potential contaminants, check evidence.txt +# ToDo: Remove potential contaminants, check evidence.txt +mq_output.peptides.loc[mask, 'Potential contaminant'].value_counts() # %% [markdown] # ### `id_map`: Find genes based on fasta file @@ -597,7 +601,7 @@ # Does a group of peptide only assigns unique set of genes? Genes can have more than one protein. # - first build groups # - then see matches (see further below) -# +# # %% peptides_with_single_gene = mq.get_peptides_with_single_gene( @@ -619,9 +623,8 @@ peptides_with_single_gene.loc[mask] # %% -_mask_con = peptides_with_single_gene.loc[mask, mq_col.PROTEINS].str.split(";" - ).apply(lambda x: [True if "CON_" in item else False for item in x] - ).apply(all) +_mask_con = peptides_with_single_gene.loc[mask, mq_col.PROTEINS].str.split(";").apply( + lambda x: [True if "CON_" in item else False for item in x]).apply(all) assert _mask_con.sum() == 0, "There are peptides resulting only from possible confounders: {}".format( ", ".join(str(x) for x in peptides_with_single_gene.loc[mask, mq_col.PROTEINS].loc[_mask_con].index)) @@ -650,7 +653,7 @@ set_of_proteins # %% -gene_data[mq_col.PROTEINS].value_counts() # combine? select first in case of a CON_ as leading razor protein? +gene_data[mq_col.PROTEINS].value_counts() # combine? select first in case of a CON_ as leading razor protein? # %% protein_id = set_of_proteins.pop() @@ -678,7 +681,7 @@ peps_in_data = gene_data.index mq.calculate_completness_for_sample( - peps_exact_cleaved=peps_exact_cleaved, + peps_exact_cleaved=peps_exact_cleaved, peps_in_data=peps_in_data) # %% [markdown] @@ -800,18 +803,26 @@ def __repr__(self): # #### Descriptics # %% -s_completeness = pd.Series(completeness_per_gene, name='completenes_by_gene') +s_completeness = pd.Series(completeness_per_gene, name='completenes_by_gene') s_completeness.describe() # %% N_BINS = 20 -ax = s_completeness.plot(kind='hist', - bins=N_BINS, - xticks=[x/100 for x in range(0, 101, 5)], - figsize=(10, 5), - rot=90, - title=f"Frequency of proportion of observed exact peptides (completness) per razor protein from 0 to 1 in {N_BINS} bins" - f"\nin sample {mq_output.folder.stem}") +ax = s_completeness.plot( + kind='hist', + bins=N_BINS, + xticks=[ + x / + 100 for x in range( + 0, + 101, + 5)], + figsize=( + 10, + 5), + rot=90, + title=f"Frequency of proportion of observed exact peptides (completness) per razor protein from 0 to 1 in {N_BINS} bins" + f"\nin sample {mq_output.folder.stem}") _ = ax.set_xlabel( "Proportion of exactly observed peptides (including up to 2 mis-cleavages)") diff --git a/project/erda_data_available.ipynb b/project/erda_data_available.ipynb index c9e9f2283..8213b7ae1 100644 --- a/project/erda_data_available.ipynb +++ b/project/erda_data_available.ipynb @@ -7,6 +7,7 @@ "metadata": {}, "outputs": [], "source": [ + "from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES\n", "import logging\n", "import matplotlib\n", "import matplotlib.pyplot as plt\n", @@ -18,7 +19,6 @@ "from vaep.logging import setup_nb_logger\n", "setup_nb_logger(level=logging.INFO)\n", "\n", - "from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES\n", "\n", "FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES" ] @@ -60,7 +60,7 @@ "outputs": [], "source": [ "peptide_counts = peptide_counter.get_df_counts()\n", - "# peptide_counts.index += 1 \n", + "# peptide_counts.index += 1\n", "peptide_counts.head()" ] }, @@ -71,7 +71,7 @@ "metadata": {}, "outputs": [], "source": [ - "peptide_counts.describe(percentiles=np.linspace(0.1,1,10))" + "peptide_counts.describe(percentiles=np.linspace(0.1, 1, 10))" ] }, { @@ -165,7 +165,7 @@ "source": [ "gene_counter = data_objects.GeneCounter(FNAME_C_GENES)\n", "gene_count = gene_counter.get_df_counts()\n", - "gene_count.head() # remove NaN entry" + "gene_count.head() # remove NaN entry" ] }, { @@ -176,7 +176,7 @@ "outputs": [], "source": [ "gene_count = gene_count.iloc[1:]\n", - "gene_count.head() " + "gene_count.head()" ] }, { @@ -186,7 +186,7 @@ "metadata": {}, "outputs": [], "source": [ - "ax = gene_counter.plot_counts(df_counts=gene_count) # provide manuelly manipulated gene counts" + "ax = gene_counter.plot_counts(df_counts=gene_count) # provide manuelly manipulated gene counts" ] } ], diff --git a/project/erda_data_available.py b/project/erda_data_available.py index 81d787108..f7decce5c 100644 --- a/project/erda_data_available.py +++ b/project/erda_data_available.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.5 +# jupytext_version: 1.15.0 # kernelspec: # display_name: vaep # language: python @@ -13,6 +13,7 @@ # --- # %% +from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES import logging import matplotlib import matplotlib.pyplot as plt @@ -24,7 +25,6 @@ from vaep.logging import setup_nb_logger setup_nb_logger(level=logging.INFO) -from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES @@ -40,11 +40,11 @@ # %% peptide_counts = peptide_counter.get_df_counts() -# peptide_counts.index += 1 +# peptide_counts.index += 1 peptide_counts.head() # %% -peptide_counts.describe(percentiles=np.linspace(0.1,1,10)) +peptide_counts.describe(percentiles=np.linspace(0.1, 1, 10)) # %% vaep.plotting.make_large_descriptors() @@ -80,12 +80,12 @@ # %% gene_counter = data_objects.GeneCounter(FNAME_C_GENES) gene_count = gene_counter.get_df_counts() -gene_count.head() # remove NaN entry +gene_count.head() # remove NaN entry # %% gene_count = gene_count.iloc[1:] -gene_count.head() +gene_count.head() # %% -ax = gene_counter.plot_counts(df_counts=gene_count) # provide manuelly manipulated gene counts +ax = gene_counter.plot_counts(df_counts=gene_count) # provide manuelly manipulated gene counts diff --git a/project/misc_FASTA_data_agg_by_gene.ipynb b/project/misc_FASTA_data_agg_by_gene.ipynb index c4733a5c7..fc31a5697 100644 --- a/project/misc_FASTA_data_agg_by_gene.ipynb +++ b/project/misc_FASTA_data_agg_by_gene.ipynb @@ -14,7 +14,9 @@ "outputs": [], "source": [ "from collections import defaultdict\n", + "import itertools\n", "import json\n", + "from pprint import pprint\n", "from tqdm.notebook import tqdm\n", "\n", "import numpy as np\n", @@ -33,7 +35,7 @@ "outputs": [], "source": [ "with open(FN_FASTA_DB) as f:\n", - " data_fasta = json.load(f)#, indent=4, sort_keys=False)\n", + " data_fasta = json.load(f) # , indent=4, sort_keys=False)\n", "len(data_fasta)" ] }, @@ -61,7 +63,7 @@ "metadata": {}, "outputs": [], "source": [ - "gene = 'ACTG1' # Actin as a contaminant protein\n", + "gene = 'ACTG1' # Actin as a contaminant protein\n", "gene_isotopes[gene]" ] }, @@ -71,7 +73,6 @@ "metadata": {}, "outputs": [], "source": [ - "from pprint import pprint\n", "for isotope in gene_isotopes[gene]:\n", " pprint(data_fasta[isotope])" ] @@ -129,7 +130,8 @@ "metadata": {}, "outputs": [], "source": [ - "alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3I0']) # Identical? Maybe check if this is more than once the case?\n", + "# Identical? Maybe check if this is more than once the case?\n", + "alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3I0'])\n", "for alignment in alignments:\n", " print(alignment)" ] @@ -149,7 +151,7 @@ "metadata": {}, "outputs": [], "source": [ - "alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3R2']) # Identical?\n", + "alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3R2']) # Identical?\n", "for alignment in alignments:\n", " print(alignment)\n", " break" @@ -161,7 +163,7 @@ "metadata": {}, "outputs": [], "source": [ - "alignments = aligner.align(sequences.loc['P63261'], sequences.loc['K7EM38']) # Identical?\n", + "alignments = aligner.align(sequences.loc['P63261'], sequences.loc['K7EM38']) # Identical?\n", "for alignment in alignments:\n", " print(alignment)\n", " break" @@ -180,13 +182,12 @@ "metadata": {}, "outputs": [], "source": [ - "import itertools\n", "peptides = {}\n", "for isotope in gene_isotopes[gene]:\n", " sequences[isotope] = data_fasta[isotope][fasta_keys.peptides][0]\n", "\n", "for peptides in itertools.zip_longest(*sequences.values, fillvalue=''):\n", - " if len(set(peptides)) == 1: \n", + " if len(set(peptides)) == 1:\n", " print(f'all identical: {peptides[0]}')\n", " else:\n", " print('\\t'.join(peptides))" @@ -199,7 +200,7 @@ "outputs": [], "source": [ "for j, peptides in enumerate(sequences.values):\n", - " if j==0:\n", + " if j == 0:\n", " set_overlap = set(peptides)\n", " else:\n", " set_overlap = set_overlap.intersection(peptides)\n", diff --git a/project/misc_FASTA_data_agg_by_gene.py b/project/misc_FASTA_data_agg_by_gene.py index 60d7a8888..072b02b90 100644 --- a/project/misc_FASTA_data_agg_by_gene.py +++ b/project/misc_FASTA_data_agg_by_gene.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.0 +# jupytext_version: 1.15.0 # kernelspec: # display_name: vaep # language: python @@ -17,7 +17,9 @@ # %% from collections import defaultdict +import itertools import json +from pprint import pprint from tqdm.notebook import tqdm import numpy as np @@ -30,7 +32,7 @@ # %% with open(FN_FASTA_DB) as f: - data_fasta = json.load(f)#, indent=4, sort_keys=False) + data_fasta = json.load(f) # , indent=4, sort_keys=False) len(data_fasta) # %% @@ -46,11 +48,10 @@ print(f"#{len(protein_wo_gene)} proteins have not gene associated: {', '.join(protein_wo_gene[:10])}, ...") # %% -gene = 'ACTG1' # Actin as a contaminant protein +gene = 'ACTG1' # Actin as a contaminant protein gene_isotopes[gene] # %% -from pprint import pprint for isotope in gene_isotopes[gene]: pprint(data_fasta[isotope]) @@ -74,7 +75,8 @@ aligner = Align.PairwiseAligner() # %% -alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3I0']) # Identical? Maybe check if this is more than once the case? +# Identical? Maybe check if this is more than once the case? +alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3I0']) for alignment in alignments: print(alignment) @@ -82,13 +84,13 @@ data_fasta['I3L1U9'][fasta_keys.seq] == data_fasta['I3L3I0'][fasta_keys.seq] # %% -alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3R2']) # Identical? +alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3R2']) # Identical? for alignment in alignments: print(alignment) break # %% -alignments = aligner.align(sequences.loc['P63261'], sequences.loc['K7EM38']) # Identical? +alignments = aligner.align(sequences.loc['P63261'], sequences.loc['K7EM38']) # Identical? for alignment in alignments: print(alignment) break @@ -97,20 +99,19 @@ # ## Unique Peptides # %% -import itertools peptides = {} for isotope in gene_isotopes[gene]: sequences[isotope] = data_fasta[isotope][fasta_keys.peptides][0] for peptides in itertools.zip_longest(*sequences.values, fillvalue=''): - if len(set(peptides)) == 1: + if len(set(peptides)) == 1: print(f'all identical: {peptides[0]}') else: print('\t'.join(peptides)) # %% for j, peptides in enumerate(sequences.values): - if j==0: + if j == 0: set_overlap = set(peptides) else: set_overlap = set_overlap.intersection(peptides) diff --git a/project/misc_FASTA_tryptic_digest.ipynb b/project/misc_FASTA_tryptic_digest.ipynb index a2d970059..a45249d10 100644 --- a/project/misc_FASTA_tryptic_digest.ipynb +++ b/project/misc_FASTA_tryptic_digest.ipynb @@ -5,7 +5,7 @@ "metadata": {}, "source": [ "# Process FASTA files\n", - "> uses only the provided fasta files in `src.config.py` by `FOLDER_FASTA` \n", + "> uses only the provided fasta files in `src.config.py` by `FOLDER_FASTA`\n", "\n", "- create theoretically considered peptides considered by search engines\n", "- dump results as human readable json to `FN_FASTA_DB` file specifed in src.config.\n", @@ -19,6 +19,7 @@ "metadata": {}, "outputs": [], "source": [ + "\n", "from collections import defaultdict, namedtuple\n", "import os\n", "import json\n", @@ -41,6 +42,7 @@ "from vaep.fasta import cleave_to_tryptic\n", "from vaep.fasta import iterFlatten\n", "from vaep.fasta import count_peptide_matches\n", + "from vaep.fasta import read_fasta\n", "from vaep.io import search_files\n", "from vaep.pandas import combine_value_counts\n", "from vaep.databases.uniprot import query_uniprot_id_mapping\n", @@ -58,7 +60,9 @@ "from config import FIGUREFOLDER\n", "from config import FN_ID_MAP\n", "from config import FN_PROT_GENE_MAP\n", - "from config import FN_PEP_TO_PROT" + "from config import FN_PEP_TO_PROT\n", + "\n", + "from config import KEY_FASTA_HEADER, KEY_FASTA_SEQ, KEY_GENE_NAME, KEY_PEPTIDES" ] }, { @@ -80,7 +84,10 @@ "test_data = {\n", " \"meta\": \">tr|A0A024R1R8|A0A024R1R8_HUMAN HCG2014768, isoform CRA_a OS=Homo sapiens OX=9606 GN=hCG_2014768 PE=4 SV=1\",\n", " \"seq\": \"MSSHEGGKKKALKQPKKQAKEMDEEEKAFKQKQKEEQKKLEVLKAKVVGKGPLATGGIKKSGKK\",\n", - " \"peptides\": [\"MSSHEGGK\", \"EMDEEEK\", \"GPLATGGIK\"],\n", + " \"peptides\": [\n", + " \"MSSHEGGK\",\n", + " \"EMDEEEK\",\n", + " \"GPLATGGIK\"],\n", "}" ] }, @@ -110,7 +117,7 @@ "\n", "- map peptide set of peptides (how to deal with mis-cleavages?)\n", " - mis-cleavages can happen both to the peptide before and after.\n", - " > `pep1, pep2, pep3, pep4, pep5` \n", + " > `pep1, pep2, pep3, pep4, pep5`\n", " > `pep1pep2, pep2pep3, pep3pep4, pep4pep5`\n", " - sliding windows can pass trough the list of peptides - should work with recursion" ] @@ -129,7 +136,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "`add_rxk` should add pattern of starting R and trailing K ? " + "`add_rxk` should add pattern of starting R and trailing K ?" ] }, { @@ -203,7 +210,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "rdx peptides are a subset of two missed cleavage sites peptides. There are omitted when two and more cleavage site can be skipped." + "rdx peptides are a subset of two missed cleavage sites peptides. There\n", + "are omitted when two and more cleavage site can be skipped." ] }, { @@ -223,7 +231,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Data Structure is no a list of list. Maybe this could be improved. Information what kind of type the peptide is from, is still interesting." + "Data Structure is no a list of list. Maybe this could be improved.\n", + "Information what kind of type the peptide is from, is still interesting." ] }, { @@ -252,9 +261,9 @@ "source": [ "### Define Setup\n", "\n", - "Set input FASTA, Output .txt name, lower legth cutoff, missed cleavages and if to report reverse. \n", + "Set input FASTA, Output .txt name, lower legth cutoff, missed cleavages and if to report reverse.\n", "\n", - "Tryptic digest of Fastas to Peptides >6 in list for matching with measured peptides " + "Tryptic digest of Fastas to Peptides >6 in list for matching with measured peptides" ] }, { @@ -313,9 +322,7 @@ "metadata": {}, "outputs": [], "source": [ - "from config import KEY_FASTA_HEADER, KEY_FASTA_SEQ, KEY_GENE_NAME, KEY_PEPTIDES\n", "\n", - "from vaep.fasta import read_fasta\n", "\n", "data_fasta = {}\n", "\n", @@ -328,7 +335,7 @@ "# }\n", "# # or dataclass\n", "# from dataclasses import make_dataclass\n", - "# FastaEntry = make_dataclass(cls_name='FastaEntry', \n", + "# FastaEntry = make_dataclass(cls_name='FastaEntry',\n", "# fields=[\n", "# (KEY_FASTA_HEADER, 'str'),\n", "# (KEY_GENE_NAME, 'str'),\n", @@ -431,6 +438,7 @@ "source": [ "test_series = pd.Series({\"A\": 4, \"B\": 1, \"C\": 0, \"D\": 4})\n", "\n", + "\n", "def get_indices_with_value(s: pd.Series, value):\n", " \"\"\"Return indices for with the value is true\"\"\"\n", " return s[s == value].index\n", @@ -443,7 +451,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Boolean Indexing, remember to set [parantheses](https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing)" + "Boolean Indexing, remember to set\n", + "[parantheses](https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing)" ] }, { @@ -577,7 +586,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Possible to join \"isoforms\" by joining all variants to one. Isoforms are numbered from the second on by appending `-i` for $i>1$, i.e. starting with `-2`. The gene name of which the protein (isoform) originate can be obtained by using [id mapping](https://www.uniprot.org/help/api_idmapping). Isoforms are not mapped automatically by Uniprot to its GENENAME, i.e. you have to strip all `-i`, e.g `-2`, `-3`, for querying. Here the protein, gene pairs are mapped to the unique protein identifiers." + "Possible to join \"isoforms\" by joining all variants to one. Isoforms are\n", + "numbered from the second on by appending `-i` for $i>1$, i.e. starting\n", + "with `-2`. The gene name of which the protein (isoform) originate can be\n", + "obtained by using [id\n", + "mapping](https://www.uniprot.org/help/api_idmapping). Isoforms are not\n", + "mapped automatically by Uniprot to its GENENAME, i.e. you have to strip\n", + "all `-i`, e.g `-2`, `-3`, for querying. Here the protein, gene pairs are\n", + "mapped to the unique protein identifiers." ] }, { @@ -722,7 +738,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Add gene names from UniProt to `id_map` DataFrame by an outer join (keeping all information based on the protein names shared by isotopes)" + "Add gene names from UniProt to `id_map` DataFrame by an outer join\n", + "(keeping all information based on the protein names shared by isotopes)" ] }, { @@ -759,10 +776,10 @@ "outputs": [], "source": [ "genes_fasta_offline = pd.DataFrame(\n", - " ((_key, _data[KEY_GENE_NAME]) for _key, _data in data_fasta.items()),\n", - " columns=[\"prot_id\", \"gene_fasta\"],\n", - " ).set_index(\"prot_id\"\n", - " ).replace('', np.nan)\n", + " ((_key, _data[KEY_GENE_NAME]) for _key, _data in data_fasta.items()),\n", + " columns=[\"prot_id\", \"gene_fasta\"],\n", + ").set_index(\"prot_id\"\n", + " ).replace('', np.nan)\n", "genes_fasta_offline.loc[genes_fasta_offline.gene_fasta.isna()]" ] }, @@ -795,7 +812,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Using the genes from the fasta file header reduces the number of missing genes, but additionally other differences arise in the comparison to the lastest version." + "Using the genes from the fasta file header reduces the number of missing\n", + "genes, but additionally other differences arise in the comparison to the\n", + "lastest version." ] }, { @@ -846,7 +865,8 @@ "source": [ "### Isotopes mapping\n", "\n", - "Isotopes are mapped now to a protein with the same name. The same can be achieved by just discarding everything behind the hypen `-`" + "Isotopes are mapped now to a protein with the same name. The same can be\n", + "achieved by just discarding everything behind the hypen `-`" ] }, { @@ -928,7 +948,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Map peptide to either identifier, common protein or gene \n" + "### Map peptide to either identifier, common protein or gene\n" ] }, { @@ -980,12 +1000,14 @@ "source": [ "### Plot histograms for different levels of abstraction\n", "\n", - "Plot counts of matched \n", + "Plot counts of matched\n", " 1. protein IDs\n", " 2. proteins (joining isoforms)\n", " 3. genes\n", - " \n", - "to their peptides. See how many unique peptides exist. The number of peptides should stay the same, so the counts do not have to be normalized." + "\n", + "to their peptides. See how many unique peptides exist. The number of\n", + "peptides should stay the same, so the counts do not have to be\n", + "normalized." ] }, { @@ -1114,7 +1136,7 @@ "ax.set_ylabel(\"peptide counts\")\n", "ax.set_xlabel(\"number of matched levels\")\n", "# ax.yaxis.set_major_formatter(\"{x:,}\")\n", - "_y_ticks = ax.set_yticks(list(range(0, 3_500_000, 500_000))) # is there a ways to transform float to int in matplotlib?\n", + "_y_ticks = ax.set_yticks(list(range(0, 3_500_000, 500_000))) # is there a ways to transform float to int in matplotlib?\n", "_y_ticks_labels = ax.set_yticklabels([f\"{x:,}\" for x in range(0, 3_500_000, 500_000)])\n", "\n", "_savefig(fig, folder=\"figures\", name=\"fasta_top4\")" @@ -1147,7 +1169,7 @@ "\n", "axes = axes.reshape((2, 2))\n", "\n", - "pad = 5 # in point\n", + "pad = 5 # in point\n", "for i in range(2):\n", " axes[-1, i].set_xlabel(\"Count of number of matches for a peptide\")\n", " axes[i, 0].set_ylabel(\"number of peptides\")\n", diff --git a/project/misc_FASTA_tryptic_digest.py b/project/misc_FASTA_tryptic_digest.py index 80dde87eb..58a49f179 100644 --- a/project/misc_FASTA_tryptic_digest.py +++ b/project/misc_FASTA_tryptic_digest.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.0 +# jupytext_version: 1.15.0 # kernelspec: # display_name: vaep # language: python @@ -14,7 +14,7 @@ # %% [markdown] # # Process FASTA files -# > uses only the provided fasta files in `src.config.py` by `FOLDER_FASTA` +# > uses only the provided fasta files in `src.config.py` by `FOLDER_FASTA` # # - create theoretically considered peptides considered by search engines # - dump results as human readable json to `FN_FASTA_DB` file specifed in src.config. @@ -22,6 +22,7 @@ # > Based on notebook received by [Annelaura Bach](https://www.cpr.ku.dk/staff/mann-group/?pure=en/persons/443836) and created by Johannes B. Müller \[[scholar](https://scholar.google.com/citations?user=Rn1OS8oAAAAJ&hl=de), [MPI Biochemistry](https://www.biochem.mpg.de/person/93696/2253)\] # %% + from collections import defaultdict, namedtuple import os import json @@ -38,6 +39,7 @@ from vaep.fasta import cleave_to_tryptic from vaep.fasta import iterFlatten from vaep.fasta import count_peptide_matches +from vaep.fasta import read_fasta from vaep.io import search_files from vaep.pandas import combine_value_counts from vaep.databases.uniprot import query_uniprot_id_mapping @@ -51,6 +53,8 @@ from config import FN_PROT_GENE_MAP from config import FN_PEP_TO_PROT +from config import KEY_FASTA_HEADER, KEY_FASTA_SEQ, KEY_GENE_NAME, KEY_PEPTIDES + # %% [markdown] # ## Core Functionality - Example # @@ -61,7 +65,10 @@ test_data = { "meta": ">tr|A0A024R1R8|A0A024R1R8_HUMAN HCG2014768, isoform CRA_a OS=Homo sapiens OX=9606 GN=hCG_2014768 PE=4 SV=1", "seq": "MSSHEGGKKKALKQPKKQAKEMDEEEKAFKQKQKEEQKKLEVLKAKVVGKGPLATGGIKKSGKK", - "peptides": ["MSSHEGGK", "EMDEEEK", "GPLATGGIK"], + "peptides": [ + "MSSHEGGK", + "EMDEEEK", + "GPLATGGIK"], } # %% [markdown] @@ -77,7 +84,7 @@ # # - map peptide set of peptides (how to deal with mis-cleavages?) # - mis-cleavages can happen both to the peptide before and after. -# > `pep1, pep2, pep3, pep4, pep5` +# > `pep1, pep2, pep3, pep4, pep5` # > `pep1pep2, pep2pep3, pep3pep4, pep4pep5` # - sliding windows can pass trough the list of peptides - should work with recursion @@ -86,7 +93,7 @@ l_peptides # %% [markdown] -# `add_rxk` should add pattern of starting R and trailing K ? +# `add_rxk` should add pattern of starting R and trailing K ? # %% last_pep = "" @@ -128,7 +135,8 @@ print("".join(example_peptides_fasta[0]), *example_peptides_fasta, sep="\n") # %% [markdown] -# rdx peptides are a subset of two missed cleavage sites peptides. There are omitted when two and more cleavage site can be skipped. +# rdx peptides are a subset of two missed cleavage sites peptides. There +# are omitted when two and more cleavage site can be skipped. # %% example_peptides_fasta = cleave_to_tryptic( @@ -138,7 +146,8 @@ example_peptides_fasta[-1] # %% [markdown] -# Data Structure is no a list of list. Maybe this could be improved. Information what kind of type the peptide is from, is still interesting. +# Data Structure is no a list of list. Maybe this could be improved. +# Information what kind of type the peptide is from, is still interesting. # %% [markdown] # ## Process Fasta Files @@ -153,9 +162,9 @@ # %% [markdown] # ### Define Setup # -# Set input FASTA, Output .txt name, lower legth cutoff, missed cleavages and if to report reverse. +# Set input FASTA, Output .txt name, lower legth cutoff, missed cleavages and if to report reverse. # -# Tryptic digest of Fastas to Peptides >6 in list for matching with measured peptides +# Tryptic digest of Fastas to Peptides >6 in list for matching with measured peptides # %% CUTOFF_LEN_PEP = 7 @@ -190,9 +199,7 @@ # ### Schema for single fasta entry # %% -from config import KEY_FASTA_HEADER, KEY_FASTA_SEQ, KEY_GENE_NAME, KEY_PEPTIDES -from vaep.fasta import read_fasta data_fasta = {} @@ -205,7 +212,7 @@ # } # # or dataclass # from dataclasses import make_dataclass -# FastaEntry = make_dataclass(cls_name='FastaEntry', +# FastaEntry = make_dataclass(cls_name='FastaEntry', # fields=[ # (KEY_FASTA_HEADER, 'str'), # (KEY_GENE_NAME, 'str'), @@ -266,6 +273,7 @@ # %% test_series = pd.Series({"A": 4, "B": 1, "C": 0, "D": 4}) + def get_indices_with_value(s: pd.Series, value): """Return indices for with the value is true""" return s[s == value].index @@ -274,7 +282,8 @@ def get_indices_with_value(s: pd.Series, value): get_indices_with_value(test_series, 4) # %% [markdown] -# Boolean Indexing, remember to set [parantheses](https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing) +# Boolean Indexing, remember to set +# [parantheses](https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing) # %% MIN_AA_IN_SEQ = 10 @@ -348,7 +357,14 @@ def get_indices_with_value(s: pd.Series, value): # ### Proteins' Isoforms # %% [markdown] -# Possible to join "isoforms" by joining all variants to one. Isoforms are numbered from the second on by appending `-i` for $i>1$, i.e. starting with `-2`. The gene name of which the protein (isoform) originate can be obtained by using [id mapping](https://www.uniprot.org/help/api_idmapping). Isoforms are not mapped automatically by Uniprot to its GENENAME, i.e. you have to strip all `-i`, e.g `-2`, `-3`, for querying. Here the protein, gene pairs are mapped to the unique protein identifiers. +# Possible to join "isoforms" by joining all variants to one. Isoforms are +# numbered from the second on by appending `-i` for $i>1$, i.e. starting +# with `-2`. The gene name of which the protein (isoform) originate can be +# obtained by using [id +# mapping](https://www.uniprot.org/help/api_idmapping). Isoforms are not +# mapped automatically by Uniprot to its GENENAME, i.e. you have to strip +# all `-i`, e.g `-2`, `-3`, for querying. Here the protein, gene pairs are +# mapped to the unique protein identifiers. # %% prot_ids = list(data_fasta.keys()) @@ -425,7 +441,8 @@ def get_indices_with_value(s: pd.Series, value): ), f"The number of proteins associated to a gene found on 11.11.2020 was 72471, now it's {len(genes)}" # %% [markdown] -# Add gene names from UniProt to `id_map` DataFrame by an outer join (keeping all information based on the protein names shared by isotopes) +# Add gene names from UniProt to `id_map` DataFrame by an outer join +# (keeping all information based on the protein names shared by isotopes) # %% id_map = id_map.merge(genes, how="outer", left_on="protein", right_index=True) @@ -440,10 +457,10 @@ def get_indices_with_value(s: pd.Series, value): # %% genes_fasta_offline = pd.DataFrame( - ((_key, _data[KEY_GENE_NAME]) for _key, _data in data_fasta.items()), - columns=["prot_id", "gene_fasta"], - ).set_index("prot_id" - ).replace('', np.nan) + ((_key, _data[KEY_GENE_NAME]) for _key, _data in data_fasta.items()), + columns=["prot_id", "gene_fasta"], +).set_index("prot_id" + ).replace('', np.nan) genes_fasta_offline.loc[genes_fasta_offline.gene_fasta.isna()] # %% @@ -460,7 +477,9 @@ def get_indices_with_value(s: pd.Series, value): id_map.loc[mask_no_gene] # %% [markdown] -# Using the genes from the fasta file header reduces the number of missing genes, but additionally other differences arise in the comparison to the lastest version. +# Using the genes from the fasta file header reduces the number of missing +# genes, but additionally other differences arise in the comparison to the +# lastest version. # %% mask_gene_diffs = id_map.gene != id_map.gene_fasta @@ -483,7 +502,8 @@ def get_indices_with_value(s: pd.Series, value): # %% [markdown] # ### Isotopes mapping # -# Isotopes are mapped now to a protein with the same name. The same can be achieved by just discarding everything behind the hypen `-` +# Isotopes are mapped now to a protein with the same name. The same can be +# achieved by just discarding everything behind the hypen `-` # %% id_map.loc[id_map.index.str.contains("-")] @@ -523,7 +543,7 @@ def get_indices_with_value(s: pd.Series, value): f"Proteins are mapped to a total number of genes of {len(set(dict_protein_to_gene.values()))}" # %% [markdown] -# ### Map peptide to either identifier, common protein or gene +# ### Map peptide to either identifier, common protein or gene # # %% @@ -548,12 +568,14 @@ def get_indices_with_value(s: pd.Series, value): # %% [markdown] # ### Plot histograms for different levels of abstraction # -# Plot counts of matched +# Plot counts of matched # 1. protein IDs # 2. proteins (joining isoforms) # 3. genes -# -# to their peptides. See how many unique peptides exist. The number of peptides should stay the same, so the counts do not have to be normalized. +# +# to their peptides. See how many unique peptides exist. The number of +# peptides should stay the same, so the counts do not have to be +# normalized. # %% USE_OFFLINE_FASTA_GENES = True @@ -610,7 +632,7 @@ def get_indices_with_value(s: pd.Series, value): ax.set_ylabel("peptide counts") ax.set_xlabel("number of matched levels") # ax.yaxis.set_major_formatter("{x:,}") -_y_ticks = ax.set_yticks(list(range(0, 3_500_000, 500_000))) # is there a ways to transform float to int in matplotlib? +_y_ticks = ax.set_yticks(list(range(0, 3_500_000, 500_000))) # is there a ways to transform float to int in matplotlib? _y_ticks_labels = ax.set_yticklabels([f"{x:,}" for x in range(0, 3_500_000, 500_000)]) _savefig(fig, folder="figures", name="fasta_top4") @@ -637,7 +659,7 @@ def get_indices_with_value(s: pd.Series, value): axes = axes.reshape((2, 2)) -pad = 5 # in point +pad = 5 # in point for i in range(2): axes[-1, i].set_xlabel("Count of number of matches for a peptide") axes[i, 0].set_ylabel("number of peptides") diff --git a/project/misc_id_mapper.py b/project/misc_id_mapper.py new file mode 100644 index 000000000..944d938bc --- /dev/null +++ b/project/misc_id_mapper.py @@ -0,0 +1,458 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.15.0 +# kernelspec: +# display_name: vaep +# language: python +# name: vaep +# --- + +# %% [markdown] +# # Analyse peptides +# +# ## Specification +# - access different levels of peptides easily +# - select training data per gene easily +# + +# %% +import json +import logging +logging.basicConfig(level=logging.INFO) # configures root logger +logger = logging.getLogger() +logger.info("test") + +# %% +import pandas as pd +from config import FN_FASTA_DB, FN_ID_MAP, FN_PEPTIDE_INTENSITIES + +# %% +id_map = pd.read_json(FN_ID_MAP, orient="split") + +mask_no_gene = id_map.gene.isna() +id_map.loc[mask_no_gene, "gene"] = "-" + + +with open(FN_FASTA_DB) as f: + data_fasta = json.load(f) + +# %% +data_peptides = pd.read_pickle(FN_PEPTIDE_INTENSITIES) + +# %% +set_peptides = set(data_peptides.columns) + +# %% [markdown] +# - switch between list of proteins with any support and non +# - set threshold of number of peptides per protein over all samples (some peptides uniquely matched to one protein in on sample is just noise -> check razor peptides) +# - show support + +# %% +from collections import defaultdict +import ipywidgets as w +from config import KEY_FASTA_HEADER, KEY_FASTA_SEQ, KEY_PEPTIDES, KEY_GENE_NAME, KEY_GENE_NAME_FASTA + +TGREEN = "\033[32m" # Green Text +RESET = "\033[0;0m" + +w_first_letter = w.Dropdown( + options=id_map[KEY_GENE_NAME_FASTA].str[0].unique()) +w_genes = w.Dropdown( + options=id_map.gene.loc[id_map[KEY_GENE_NAME_FASTA].str[0] == w_first_letter.value].unique(), + value='ACTB' +) + +mask = id_map.gene == w_genes.value +selected = id_map.loc[mask, "protein"] + + +w_proteins_ids = w.Dropdown(options=selected.index) +w_protein = w.Dropdown(options=selected.unique()) + + +def update_gene_list(first_letter): + """Update proteins when new gene is selected""" + mask_selected_genes = id_map[KEY_GENE_NAME_FASTA].str[0] == w_first_letter.value + w_genes.options = id_map.gene.loc[mask_selected_genes].unique() + + +_ = w.interactive_output(update_gene_list, {"first_letter": w_first_letter}) + + +def update_protein_list(gene): + mask = id_map[KEY_GENE_NAME_FASTA] == gene + selected = id_map.loc[mask, "protein"] + w_protein.options = selected.unique() +# w_proteins_ids.options = selected.loc[selected == w_protein.value].index + + +_ = w.interactive_output(update_protein_list, {"gene": w_genes}) + + +def update_protein_id_list(protein): + """Update isotope list when protein is selected""" + mask = id_map.protein == w_protein.value + selected = id_map.protein.loc[mask] + w_proteins_ids.options = selected.index + +_ = w.interactive_output(update_protein_id_list, {'protein': w_protein}) + +d_peptides_observed_prot_id = defaultdict(list) + +def show_sequences(prot_id): + _data = data_fasta[prot_id] + print(f"Protein_ID on Uniport: {prot_id}") + print(f"HEADER: {_data[KEY_FASTA_HEADER]}") +# print(f"Seq : {_data[KEY_FASTA_SEQ]}") + annotate_seq = "Peptides: " + global d_peptides_observed_prot_id + for i, _l in enumerate(_data[KEY_PEPTIDES]): + annotate_seq += f"\nNo. of missed K or R: {i}" + prot_seq_annotated = _data[KEY_FASTA_SEQ] + for j, _pep in enumerate(_l): + if _pep in set_peptides: + d_peptides_observed_prot_id[prot_id].append(_pep) + _pep_in_green = TGREEN + f"{_pep}" + RESET + prot_seq_annotated = prot_seq_annotated.replace(_pep, _pep_in_green) + _pep = _pep_in_green + if j==0: + annotate_seq += "\n\t" + _pep + else: + annotate_seq += ",\n\t" + _pep + print(f"Seq {i}: {prot_seq_annotated}") + print(annotate_seq) + + + display(data_peptides[d_peptides_observed_prot_id[prot_id]].dropna(how='all')) + +w_out = w.interactive_output(show_sequences, {"prot_id": w_proteins_ids}) + +label_first_letter = w.Label(value='First letter of Gene') +label_genes = w.Label('Gene') +label_protein = w.Label('Protein') +label_proteins_ids = w.Label('Protein Isotopes') + +panel_levels = w.VBox([ + w.HBox([ + w.VBox([label_first_letter, w_first_letter]), + w.VBox([label_genes, w_genes]), + w.VBox([label_protein, w_protein]), + w.VBox([label_proteins_ids, w_proteins_ids]) + ]), + w_out] +) +panel_levels + +# %% [markdown] +# - relatively short peptides resulting from one missed cleaveage, do not appear in the upper part. + +# %% [markdown] +# - `gene` `->` `Protein_ID` (contains information of `gene` `->` `protein_isotopes` +# - `protein_ID` `->` `sequences` (`FN_FASTA_DB`) + +# %% +import pickle +from tqdm.notebook import tqdm +from config import FN_PROTEIN_SUPPORT_MAP, FN_PROTEIN_SUPPORT_FREQ +try: + df_protein_support = pd.read_pickle(FN_PROTEIN_SUPPORT_MAP) + with open(FN_PROTEIN_SUPPORT_FREQ, 'rb') as f: + d_protein_support_freq = pickle.load(f) +except FileNotFoundError: + from vaep.utils import sample_iterable + d_protein_support = {} + d_protein_support_freq = {} + for prot_id in tqdm(data_fasta.keys()): + _data = data_fasta[prot_id] + peptides_measured = [] + for i, _l in enumerate(_data[KEY_PEPTIDES]): + for _pep in _l: + if _pep in set_peptides: + peptides_measured.append(_pep) + _d_protein_support = {} + _df_support_protein = data_peptides[peptides_measured].dropna(how='all') + + _n_samples = len(_df_support_protein) + if _n_samples > 0: + _d_protein_support['N_samples'] = _n_samples + d_protein_support_freq[prot_id] = _df_support_protein.notna().sum().to_dict() + d_protein_support[prot_id] = _d_protein_support + else: + d_protein_support[prot_id] = None + + df_protein_support = pd.DataFrame(d_protein_support).T.dropna() + df_protein_support = df_protein_support.join(id_map) + df_protein_support.to_pickle(FN_PROTEIN_SUPPORT_MAP) + + with open(FN_PROTEIN_SUPPORT_FREQ, 'wb') as f: + pickle.dump(d_protein_support_freq, f) + +# %% +l_proteins_good_support = df_protein_support.sort_values(by='N_samples').tail(100).index.to_list() + +# %% +d_protein_support_freq['I3L3I0'] + +# %% [markdown] +# ## Connect to experimental peptide data +# +# Check if counts by `data_fasta`. + +# %% +from tqdm.notebook import tqdm + +counts_observed_by_missed_cleavages = {} +for _protein_id, _data in tqdm(data_fasta.items()): + _peptides = _data[KEY_PEPTIDES] + _counts = {} + for i, _l in enumerate(_peptides): + _counts[i] = 0 + for _pep in _l: + if _pep in set_peptides: + _counts[i] += 1 + counts_observed_by_missed_cleavages[_protein_id] = _counts + +# %% +df_counts_observed_by_missed_cleavages = pd.DataFrame( + counts_observed_by_missed_cleavages +).T + +# %% +import matplotlib.pyplot as plt +from matplotlib import table + +fig, axes = plt.subplots(ncols=2, gridspec_kw={"width_ratios": [5, 1], "wspace": 0.2}, figsize=(10,4)) + +_counts_summed = df_counts_observed_by_missed_cleavages.sum() +_counts_summed.name = "frequency" + +ax = axes[0] +_ = _counts_summed.plot(kind="bar", ax=ax) +ax.set_xlabel("peptides from n miscleavages") +ax.set_ylabel("frequency") + +ax = axes[1] +ax.axis("off") +_ = pd.plotting.table(ax=ax, data=_counts_summed, loc="best", colWidths=[1], edges='open') +_ = fig.suptitle('Peptides frequencies') + +# %% [markdown] +# These are unnormalized counts in the meaning of that _razor_ peptides are counted as often as they are matched. + +# %% +mask = df_counts_observed_by_missed_cleavages != 0 +df_prot_observed = df_counts_observed_by_missed_cleavages.replace(0, pd.NA) + +# %% +df_prot_observed = df_prot_observed.dropna(axis=0, how="all") +df_prot_observed = df_prot_observed.fillna(0) +df_prot_observed = df_prot_observed.convert_dtypes() + +# %% +from vaep.pandas import combine_value_counts + +combine_value_counts(df_prot_observed) + +# %% +freq_pep_mapped_to_protID = df_prot_observed.sum(axis=1).value_counts() +freq_pep_mapped_to_protID = freq_pep_mapped_to_protID.sort_index() + +# %% +freq_pep_mapped_to_protID + +# %% [markdown] +# ### Genes with support in data +# +# try software to identify the _most likely_ protein. OpenMS or russian alternative? + +# %% + +# %% [markdown] +# ## Imputation: Train model +# +# > Select Gene or Protein +# +# As the samples are all obtained from the same biological sample (in principal), the single run should somehow be comparable. +# An description of variablity (from the Data Scientist perspective) can highlight some commenly known facts about proteomics experiments: +# - batch effects: Measurements on consecutive days are have to be normalized to each other +# - scoring: PSM are assigned to a peptide based on a score. Small variations can lead to different assignments +# +# Can a complex representation of a sample level out experimental variation on an in principle comparable data. +# +# ### Strategy +# - first start using peptides from single Protein_IDs +# - then move to all models from genes +# - explore structure + +# %% +import torch + +# %% +d_peptides_observed_prot_id + +# %% +w_select_proteins_good_support = w.Dropdown(options=l_proteins_good_support) +w_select_proteins_queried = w.Dropdown(options=list(d_peptides_observed_prot_id.keys())) +w.HBox( + [ + w.VBox( + [ + w.Label(f"Top {len(l_proteins_good_support)} covered proteins"), + w_select_proteins_good_support, + ] + ), + w.VBox([w.Label("Queried proteins from above"), w_select_proteins_queried]), + ] +) +# select from top100 or above selection + +# %% [markdown] +# Idea: Select a protein which leads to training. Each selection will create a dump of the selected data, which can be used in the `XZY.ipynb` for model fine-tuning. + +# %% +prot_id = w_select_proteins_good_support.value +id_map.loc[prot_id] + +# %% +prot_id = 'P00338' # 'I3L3I0' # w_select_proteins_queried.value # +_protein, _gene, _ = id_map.loc[prot_id] +# _gene_fasta + +# %% +w_first_letter.value = _gene[0] +w_genes.value = _gene +w_protein.value = _protein +w_proteins_ids.value = prot_id + +# %% +peptides_measured = d_peptides_observed_prot_id[prot_id] +n_peptides_in_selection = len(peptides_measured) +print(f"Selected a total of {n_peptides_in_selection} peptides.") + +# %% +data_peptides[peptides_measured].notna().sum(axis=1).value_counts().sort_index() + +# %% +PROP_DATA_COMPLETENESS = 0.75 +mask_samples_selected = data_peptides[peptides_measured].notna().sum(axis=1) >= int(n_peptides_in_selection * 0.75) +print(f"Using a share of at least {PROP_DATA_COMPLETENESS}, i.e. at least {int(n_peptides_in_selection * 0.75)} out of {n_peptides_in_selection}.", + f"In total {mask_samples_selected.sum()} samples.", sep="\n") + +# %% +from config import PROTEIN_DUMPS +_ = data_peptides.loc[mask_samples_selected, peptides_measured] +_.to_json(PROTEIN_DUMPS / f"{prot_id}.pkl") +_ + +# %% +import vaep +from vaep.transform import log + +peptides_selected_log10 = data_peptides.loc[mask_samples_selected, peptides_measured].apply(log) # selected in widget overview above +peptides_selected_log10 + +# %% [markdown] +# > The data to be seen here should be **assigned** peptides. Razor peptides are for now not put to one or the other protein (focus only on unique peptides?). + +# %% [markdown] +# ### Hyperparameters + +# %% +n_samples, n_features = peptides_selected_log10.shape + +# %% +from vaep.models.cmd import parser + +BATCH_SIZE = 16 +EPOCHS = 600 +args = ['--batch-size', str(BATCH_SIZE), '--seed', '43', '--epochs', str(EPOCHS), '--log-interval', str(BATCH_SIZE)] +args = parser.parse_args(args) +args.cuda = not args.no_cuda and torch.cuda.is_available() +args + +# %% +torch.manual_seed(args.seed) +device = torch.device("cuda" if args.cuda else "cpu") +device = torch.device("cpu") + +# %% +# torch.device? + +# %% [markdown] +# ### Dataset and DataLoader +# +# The `torch.utils.data.Dataset` can load data into memory, or just create a mapping to data somewhere to be continously loaded by the `torch.utils.data.DataLoader`. + +# %% +peptide_intensities = peptides_selected_log10 +detection_limit = float(int(peptide_intensities.min().min())) +detection_limit + +# %% +# from vaep.model import PeptideDatasetInMemory + +from torch.utils.data import Dataset +class PeptideDatasetInMemory(Dataset): + """Peptide Dataset fully in memory.""" + + def __init__(self, data: pd.DataFrame, fill_na=0): + self.mask_obs = torch.from_numpy(data.notna().values) + data = data.fillna(fill_na) + self.peptides = torch.from_numpy(data.values) + self.length_ = len(data) + + def __len__(self): + return self.length_ + + def __getitem__(self, idx): + return self.peptides[idx], self.mask_obs[idx] + + +dataset_in_memory = PeptideDatasetInMemory(peptide_intensities.copy(), detection_limit) + +# %% +kwargs = {'num_workers': 1, 'pin_memory': True} if device=='cuda' else {} +train_loader = torch.utils.data.DataLoader( + dataset=dataset_in_memory, + batch_size=args.batch_size, shuffle=True, **kwargs) + +# %% +for i, (data, mask) in enumerate(train_loader): + print("Nummber of samples in mini-batch: {}".format(len(data)), + "\tObject-Type: {}".format(type(mask))) +# print(data) +# print(mask) + break + +# %% +data[~mask] = 0 +plt.imshow(data) + +# %% [markdown] +# create logged information for tensorboard, see tutorial and docs. + +# %% +from datetime import datetime +from torch.utils.tensorboard import SummaryWriter +writer = SummaryWriter(f'runs/{prot_id}_{format(datetime.now(), "%y%m%d_%H%M")}') + +# %% +writer.add_image(f'{len(data)} samples heatmap', data, dataformats='HW') + +# %% +# import importlib; importlib.reload(vaep.model) +from IPython.core.debugger import set_trace + +from torch import optim +from vaep.models.ae import VAE +from vaep.models.ae import loss_function + +model = VAE(n_features=n_features, n_neurons=30).double().to(device) +writer.add_graph(model, input_to_model=data) + +optimizer = optim.Adam(model.parameters(), lr=1e-4) diff --git a/project/misc_illustrations.ipynb b/project/misc_illustrations.ipynb index dd7e6350b..3e09a695d 100644 --- a/project/misc_illustrations.ipynb +++ b/project/misc_illustrations.ipynb @@ -36,9 +36,9 @@ "source": [ "plt.rcParams.update({'xtick.labelsize': 'xx-large',\n", " 'ytick.labelsize': 'xx-large',\n", - " 'axes.titlesize' : 'xx-large',\n", - " 'axes.labelsize' : 'xx-large',\n", - " })\n", + " 'axes.titlesize': 'xx-large',\n", + " 'axes.labelsize': 'xx-large',\n", + " })\n", "# {k:v for k,v in plt.rcParams.items() if 'tick' in k and 'size' in k}" ] }, @@ -63,16 +63,16 @@ "mu = 25.0\n", "stddev = 1.0\n", "\n", - "x = np.linspace(mu -5, mu + 5, num=101)\n", + "x = np.linspace(mu - 5, mu + 5, num=101)\n", "\n", "y_normal = scipy.stats.norm.pdf(x, loc=mu, scale=stddev)\n", "\n", - "mu_shifted = mu - (1.8*stddev)\n", - "stddev_shifted = 0.3*stddev\n", + "mu_shifted = mu - (1.8 * stddev)\n", + "stddev_shifted = 0.3 * stddev\n", "print(f\"Downshifted: {mu_shifted = }, {stddev_shifted = }\")\n", - "y_impute = scipy.stats.norm.pdf(x, loc=mu - (1.8*stddev), scale=0.3*stddev)\n", + "y_impute = scipy.stats.norm.pdf(x, loc=mu - (1.8 * stddev), scale=0.3 * stddev)\n", "\n", - "colors = plt.cm.viridis([0.25,0.75]) \n", + "colors = plt.cm.viridis([0.25, 0.75])\n", "\n", "fig, ax = plt.subplots(1, 1, figsize=(5, 4))\n", "\n", @@ -106,7 +106,8 @@ "\n", "- what does log2 transformation mean for the error\n", "\n", - "If the error is calculated in log2 space, the larger values have to be predicted with higher precision (in comparison to the original space)" + "If the error is calculated in log2 space, the larger values have to be\n", + "predicted with higher precision (in comparison to the original space)" ] }, { @@ -115,22 +116,23 @@ "metadata": {}, "outputs": [], "source": [ - "def get_original_error_log2(x:float, error_log2:float):\n", - " return 2 ** (np.log2(x) + error_log2) - x \n", + "def get_original_error_log2(x: float, error_log2: float):\n", + " return 2 ** (np.log2(x) + error_log2) - x\n", + "\n", "\n", "print(\n", " f\"{get_original_error_log2(1e9, 0.5) = :,.1f}\",\n", " f\"{get_original_error_log2(1e8, 0.5) = :,.1f}\",\n", " sep='\\n'\n", - " )" + ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "If we try to find the rel log2 error equalling the original error, this can be done by \n", - "equating: \n", + "If we try to find the rel log2 error equalling the original error, this can be done by\n", + "equating:\n", "\n", "$$ \\exp(\\ln(a)+e) - a = \\exp(\\ln(a)+e^*) - b $$\n", "\n", @@ -147,12 +149,13 @@ "source": [ "def rel_error(measurment, log_error, other_measurment):\n", " numerator = 2 ** (np.log2(measurment) + log_error)\n", - " numerator-=measurment\n", - " numerator+=other_measurment\n", - " \n", + " numerator -= measurment\n", + " numerator += other_measurment\n", + "\n", " denominator = other_measurment\n", " return np.log2(numerator / denominator)\n", "\n", + "\n", "rel_error = rel_error(1.e9, 0.5, 1e8)\n", "print(f\"{rel_error = :.3f}\")" ] @@ -167,14 +170,14 @@ " f\"0.500 rel to 1e9: {get_original_error_log2(1e9, 0.5) :,.1f}\",\n", " f\"{rel_error:.3f} rel to 1e8: {get_original_error_log2(1e8, rel_error) :,.1f}\",\n", " sep='\\n'\n", - " )" + ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "So the relative error of 0.5 for $10^9$ is five times larger for $10^8$ in the logspace, \n", + "So the relative error of 0.5 for $10^9$ is five times larger for $10^8$ in the logspace,\n", "whereas the error in the original space is the same" ] }, diff --git a/project/misc_illustrations.py b/project/misc_illustrations.py index 55328e65d..e63c68278 100644 --- a/project/misc_illustrations.py +++ b/project/misc_illustrations.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.14.0 +# jupytext_version: 1.15.0 # kernelspec: # display_name: Python 3 # language: python @@ -27,9 +27,9 @@ # %% plt.rcParams.update({'xtick.labelsize': 'xx-large', 'ytick.labelsize': 'xx-large', - 'axes.titlesize' : 'xx-large', - 'axes.labelsize' : 'xx-large', - }) + 'axes.titlesize': 'xx-large', + 'axes.labelsize': 'xx-large', + }) # {k:v for k,v in plt.rcParams.items() if 'tick' in k and 'size' in k} # %% [markdown] @@ -42,16 +42,16 @@ mu = 25.0 stddev = 1.0 -x = np.linspace(mu -5, mu + 5, num=101) +x = np.linspace(mu - 5, mu + 5, num=101) y_normal = scipy.stats.norm.pdf(x, loc=mu, scale=stddev) -mu_shifted = mu - (1.8*stddev) -stddev_shifted = 0.3*stddev +mu_shifted = mu - (1.8 * stddev) +stddev_shifted = 0.3 * stddev print(f"Downshifted: {mu_shifted = }, {stddev_shifted = }") -y_impute = scipy.stats.norm.pdf(x, loc=mu - (1.8*stddev), scale=0.3*stddev) +y_impute = scipy.stats.norm.pdf(x, loc=mu - (1.8 * stddev), scale=0.3 * stddev) -colors = plt.cm.viridis([0.25,0.75]) +colors = plt.cm.viridis([0.25, 0.75]) fig, ax = plt.subplots(1, 1, figsize=(5, 4)) @@ -75,22 +75,24 @@ # # - what does log2 transformation mean for the error # -# If the error is calculated in log2 space, the larger values have to be predicted with higher precision (in comparison to the original space) +# If the error is calculated in log2 space, the larger values have to be +# predicted with higher precision (in comparison to the original space) # %% -def get_original_error_log2(x:float, error_log2:float): - return 2 ** (np.log2(x) + error_log2) - x +def get_original_error_log2(x: float, error_log2: float): + return 2 ** (np.log2(x) + error_log2) - x + print( f"{get_original_error_log2(1e9, 0.5) = :,.1f}", f"{get_original_error_log2(1e8, 0.5) = :,.1f}", sep='\n' - ) +) # %% [markdown] -# If we try to find the rel log2 error equalling the original error, this can be done by -# equating: +# If we try to find the rel log2 error equalling the original error, this can be done by +# equating: # # $$ \exp(\ln(a)+e) - a = \exp(\ln(a)+e^*) - b $$ # @@ -101,12 +103,13 @@ def get_original_error_log2(x:float, error_log2:float): # %% def rel_error(measurment, log_error, other_measurment): numerator = 2 ** (np.log2(measurment) + log_error) - numerator-=measurment - numerator+=other_measurment - + numerator -= measurment + numerator += other_measurment + denominator = other_measurment return np.log2(numerator / denominator) + rel_error = rel_error(1.e9, 0.5, 1e8) print(f"{rel_error = :.3f}") @@ -115,10 +118,10 @@ def rel_error(measurment, log_error, other_measurment): f"0.500 rel to 1e9: {get_original_error_log2(1e9, 0.5) :,.1f}", f"{rel_error:.3f} rel to 1e8: {get_original_error_log2(1e8, rel_error) :,.1f}", sep='\n' - ) +) # %% [markdown] -# So the relative error of 0.5 for $10^9$ is five times larger for $10^8$ in the logspace, +# So the relative error of 0.5 for $10^9$ is five times larger for $10^8$ in the logspace, # whereas the error in the original space is the same # %% [markdown] diff --git a/vaep/analyzers/__init__.py b/vaep/analyzers/__init__.py index 4274cfd4d..c50b18b25 100644 --- a/vaep/analyzers/__init__.py +++ b/vaep/analyzers/__init__.py @@ -1,9 +1,10 @@ from types import SimpleNamespace -from . import diff_analysis +from . import diff_analysis from . import compare_predictions __all__ = ['diff_analysis', 'compare_predictions', 'Analysis'] + class Analysis(SimpleNamespace): - pass \ No newline at end of file + pass diff --git a/vaep/analyzers/analyzers.py b/vaep/analyzers/analyzers.py index 3f0609dfa..7dbd95917 100644 --- a/vaep/analyzers/analyzers.py +++ b/vaep/analyzers/analyzers.py @@ -31,22 +31,22 @@ def verify_df(df, - fname, - index_col:str, # could be potentially 0 for the first column - verify_fname: bool = False, - usecols=None, - ): + fname, + index_col: str, # could be potentially 0 for the first column + verify_fname: bool = False, + usecols=None, + ): if usecols and isinstance(index_col, str): assert index_col in usecols, 'Add index_col to usecols Sequence' if verify_fname: if not len(df.shape) == 2: raise ValueError(f"Expected 2 -dimensional array, not {len(df.shape)} -dimensional," - f" of type: {type(df)}") + f" of type: {type(df)}") N, M = df.shape assert f'N{N:05d}' in str(fname) and f'M{M:05d}' in str(fname), \ ("Filename number don't match loaded numbers: " f"{fname} should contain N{N} and M{M}") - + class AnalyzePeptides(SimpleNamespace): """Namespace for current analysis @@ -61,7 +61,7 @@ class AnalyzePeptides(SimpleNamespace): Many more attributes are set dynamically depending on the concrete analysis. """ - def __init__(self, data:pd.DataFrame, + def __init__(self, data: pd.DataFrame, is_log_transformed: bool = False, is_wide_format: bool = True, ind_unstack: str = '',): if not is_wide_format: @@ -115,7 +115,7 @@ def from_pickle(cls, fname: str, def get_consecutive_dates(self, n_samples, seed=42): """Select n consecutive samples using a seed. - + Updated the original DataFrame attribute: df """ self.df.sort_index(inplace=True) @@ -138,7 +138,11 @@ def df_long(self): return self._df_long return self.to_long_format(colname_values='intensity', index_name=self.index_col) - def to_long_format(self, colname_values: str = 'intensity', index_name: str = 'Sample ID', inplace: str = False) -> pd.DataFrame: + def to_long_format( + self, + colname_values: str = 'intensity', + index_name: str = 'Sample ID', + inplace: str = False) -> pd.DataFrame: """[summary] Parameters @@ -178,7 +182,11 @@ def to_long_format(self, colname_values: str = 'intensity', index_name: str = 'S def df_wide(self): return self.to_wide_format() - def to_wide_format(self, columns: str = 'Sample ID', name_values: str = 'intensity', inplace: bool = False) -> pd.DataFrame: + def to_wide_format( + self, + columns: str = 'Sample ID', + name_values: str = 'intensity', + inplace: bool = False) -> pd.DataFrame: """[summary] Parameters @@ -197,11 +205,11 @@ def to_wide_format(self, columns: str = 'Sample ID', name_values: str = 'intensi """ """Build wide data view. - + Return df attribute in case this is in wide-format. If df attribute is in long-format this is used. If df is wide, but long-format exist, then the wide format is build. - - + + """ if self.is_wide_format: return self.df @@ -264,15 +272,14 @@ def get_PCA(self, n_components=2, imputer=SimpleImputer): def calculate_PCs(self, new_df, is_wide=True): if not is_wide: - new_df = new_df.unstack(new_df.index.names[1:]) - + new_df = new_df.unstack(new_df.index.names[1:]) + X = self.imputer_.transform(new_df) X = _add_indices(X, new_df) PCs = self.pca_.transform(X) PCs = _add_indices(PCs, new_df, index_only=True) PCs.columns = [f'PC {i+1}' for i in range(PCs.shape[-1])] - return PCs - + return PCs def plot_pca(self,): """Create principal component plot with three heatmaps showing @@ -294,7 +301,8 @@ def plot_pca(self,): self.dim = Dim(*self.df.shape) fig.suptitle( - f'First two Principal Components of {self.dim.M} most abundant peptides \n for {self.dim.N} samples', fontsize=30) + f'First two Principal Components of {self.dim.M} most abundant peptides \n for {self.dim.N} samples', + fontsize=30) # by instrument ax = axes[0] @@ -401,14 +409,14 @@ def _plot(self, fct, meta_key: str, save: bool = True): title=f'{self.model_name} latent space PCA of {self.latent_dim} dimensions by {meta_key}') if save: vaep.plotting._savefig(fig, name=f'{self.model_name}_latent_by_{meta_key}', - folder=self.folder) + folder=self.folder) return fig, ax # def read_csv(fname:str, nrows:int, index_col:str=None)-> pd.DataFrame: # return pd.read_csv(fname, index_col=index_col, low_memory=False, nrows=nrows) -def build_metadata_df(filenames:pd.Index) -> pd.DataFrame: +def build_metadata_df(filenames: pd.Index) -> pd.DataFrame: """Build a DataFrame based on a list of strings (an Index) to parse. Is strongly coupled to the analysis context. @@ -422,17 +430,18 @@ def build_metadata_df(filenames:pd.Index) -> pd.DataFrame: pd.DataFrame A DataFrame with the parsed metadata. """ - + d_meta = metadata.get_metadata_from_filenames(filenames) df_meta = pd.DataFrame.from_dict(d_meta, orient='index') df_meta.index.name = filenames.name return df_meta + def get_consecutive_data_indices(df, n_samples): index = df.sort_index().index start_sample = len(index) - n_samples start_sample = random.randint(0, start_sample) - return df.loc[index[start_sample:start_sample+n_samples]] + return df.loc[index[start_sample:start_sample + n_samples]] def corr_lower_triangle(df): @@ -453,13 +462,13 @@ def plot_corr_histogram(corr_lower_triangle, bins=10): ax.yaxis.set_major_formatter("{x:,.0f}") ax = axes[1] plt.axis('off') - data = values.describe(percentiles=np.linspace(0.1,1,10)).round(2) + data = values.describe(percentiles=np.linspace(0.1, 1, 10)).round(2) data.name = '' _ = pd.plotting.table(ax=ax, data=data, loc="best", edges="open") return fig, axes -def run_pca(df_wide:pd.DataFrame, n_components:int=2) -> Tuple[pd.DataFrame, PCA]: +def run_pca(df_wide: pd.DataFrame, n_components: int = 2) -> Tuple[pd.DataFrame, PCA]: """Run PCA on DataFrame and return result. Parameters @@ -531,10 +540,10 @@ def seaborn_scatter(df, ax, seaborn.scatterplot(x=df[cols[0]], y=df[cols[1]], hue=meta, ax=ax, palette='deep', s=size, alpha=alpha) _ = ax.legend(fontsize=fontsize, - title_fontsize=fontsize, - markerscale=0.4, - title=meta.name, - ) + title_fontsize=fontsize, + markerscale=0.4, + title=meta.name, + ) ax.set_title(title, fontsize=fontsize) return ax @@ -546,9 +555,9 @@ def scatter_plot_w_dates(ax, df, size=2): """plot first vs. second column in DataFrame. Use dates to color data. - - - + + + errors : {'ignore', 'raise', 'coerce'}, default 'raise' Passed on to pandas.to_datetime - If 'raise', then invalid parsing will raise an exception. @@ -576,7 +585,7 @@ def scatter_plot_w_dates(ax, df, def add_date_colorbar(mappable, ax): loc = mdates.AutoDateLocator() cbar = ax.get_figure().colorbar(mappable, ax=ax, ticks=loc, - format=mdates.AutoDateFormatter(loc)) + format=mdates.AutoDateFormatter(loc)) return cbar diff --git a/vaep/analyzers/compare_predictions.py b/vaep/analyzers/compare_predictions.py index ea0d16935..75878537d 100644 --- a/vaep/analyzers/compare_predictions.py +++ b/vaep/analyzers/compare_predictions.py @@ -24,7 +24,7 @@ def load_predictions(pred_files: List, shared_columns=['observed']): def load_split_prediction_by_modelkey(experiment_folder: Path, split: str, - model_keys:list[str], + model_keys: list[str], allow_missing=False, shared_columns: list[str] = None): """Load predictions from a list of models. @@ -63,7 +63,7 @@ def load_split_prediction_by_modelkey(experiment_folder: Path, return load_predictions(pred_files, shared_columns=shared_columns) -def load_single_csv_pred_file(fname:str|Path, value_name:str='intensity') -> pd.Series: +def load_single_csv_pred_file(fname: str | Path, value_name: str = 'intensity') -> pd.Series: """Load a single pred file from a single model. Last column are measurments, other are index. @@ -79,7 +79,7 @@ def load_single_csv_pred_file(fname:str|Path, value_name:str='intensity') -> pd. pd.Series measurments as a single column with set indices """ - pred = pd.read_csv(fname) # getattr for other file formats + pred = pd.read_csv(fname) # getattr for other file formats pred = pred.set_index(pred.columns[:-1].tolist()) pred = pred.squeeze() pred.name = value_name diff --git a/vaep/analyzers/diff_analysis.py b/vaep/analyzers/diff_analysis.py index deafe4311..6b115f6ba 100644 --- a/vaep/analyzers/diff_analysis.py +++ b/vaep/analyzers/diff_analysis.py @@ -31,7 +31,7 @@ def select_raw_data(df: pd.DataFrame, return df, Cutoffs(min_sample_for_feat, min_feat_per_sample) -def select_feat(df_qc:pd.DataFrame, threshold:float=0.4, axis:int=0): +def select_feat(df_qc: pd.DataFrame, threshold: float = 0.4, axis: int = 0): qc_cv_feat = df_qc.std(axis=axis) / df_qc.mean(axis=axis) mask = qc_cv_feat < threshold - return qc_cv_feat.loc[mask].index \ No newline at end of file + return qc_cv_feat.loc[mask].index diff --git a/vaep/analyzers/metadata.py b/vaep/analyzers/metadata.py index 27cb60906..4e843093d 100644 --- a/vaep/analyzers/metadata.py +++ b/vaep/analyzers/metadata.py @@ -37,7 +37,7 @@ assert re.search(regex_not_researcher, 'MA').group() == 'MA' assert re.search(regex_not_researcher, 'QC').group() == 'QC' assert re.search(regex_not_researcher, 'MA_OFF').group() == 'MA' -assert re.search(regex_not_researcher, '_LiNi_') == None +assert re.search(regex_not_researcher, '_LiNi_') is None type_run = {'MA': 'MNT', diff --git a/vaep/databases/__init__.py b/vaep/databases/__init__.py index 1a1fb4a49..e28e2c7c8 100644 --- a/vaep/databases/__init__.py +++ b/vaep/databases/__init__.py @@ -1,2 +1 @@ from . import uniprot - diff --git a/vaep/databases/diseases.py b/vaep/databases/diseases.py index edea11912..f4800f76f 100644 --- a/vaep/databases/diseases.py +++ b/vaep/databases/diseases.py @@ -3,7 +3,8 @@ logger = logging.getLogger(__name__) -def get_disease_association(doid:int, limit:int=1000): + +def get_disease_association(doid: int, limit: int = 1000): params = {'type1': -26, 'type2': 'value2', 'id1': f'DOID:{doid}', @@ -11,8 +12,8 @@ def get_disease_association(doid:int, limit:int=1000): 'limit': limit, 'format': 'json'} diseases_url_all = 'https://api.jensenlab.org/Integration' - - r = requests.get(diseases_url_all, params=params) + + r = requests.get(diseases_url_all, params=params) if r.status_code == 200: data, is_there_more = r.json() else: diff --git a/vaep/databases/uniprot.py b/vaep/databases/uniprot.py index 123c14ae2..65c03270b 100644 --- a/vaep/databases/uniprot.py +++ b/vaep/databases/uniprot.py @@ -179,11 +179,11 @@ def query_uniprot_id_mapping(query_list: list, FROM='UniProtKB_AC-ID', TO='Gene_ """Query Uniprot ID mappings programatically (utility function) See availabe mappings: https://www.uniprot.org/help/api_idmapping Function is programmed to query gene IDs based on protein IDs. - + Parameters ---------- query_list : list - list of strings containing queries in format specified + list of strings containing queries in format specified in FROM parameter. FROM : str, optional Format of string-ids in query_list, by default 'ACC+ID' @@ -191,7 +191,7 @@ def query_uniprot_id_mapping(query_list: list, FROM='UniProtKB_AC-ID', TO='Gene_ Format to which strings-ids should be matched with, by default 'GENENAME' FORMAT : str, optional Separator for Uniprot-ID, by default 'tab' - + Returns ------- list: @@ -208,7 +208,7 @@ def query_uniprot_id_mapping(query_list: list, FROM='UniProtKB_AC-ID', TO='Gene_ if __name__ == "__main__": - ids= ['A0A075B6I0', 'A0A075B6I1', 'A0A075B6I6', 'A0A075B6I9',] + ids = ['A0A075B6I0', 'A0A075B6I1', 'A0A075B6I6', 'A0A075B6I9',] results = query_uniprot_id_mapping(ids) print(results) # {'A0A075B6I0': 'IGLV8-61', 'A0A075B6I1': 'IGLV4-60', 'A0A075B6I6': 'IGLV1-50', 'A0A075B6I9': 'IGLV7-46'} diff --git a/vaep/io/__init__.py b/vaep/io/__init__.py index 5371ec649..21cfc5518 100644 --- a/vaep/io/__init__.py +++ b/vaep/io/__init__.py @@ -15,9 +15,10 @@ logger = logging.getLogger(__name__) logger.info(f"Calling from {__name__}") + def search_files(path='.', query='.txt'): - """Uses Pathlib to find relative to path files - with the query text in their file names. Returns + """Uses Pathlib to find relative to path files + with the query text in their file names. Returns the path relative to the specified path. Parameters @@ -30,7 +31,7 @@ def search_files(path='.', query='.txt'): Returns ------- list - list with files as string containig query key. + list with files as string containig query key. """ path = Path(path) files = [] @@ -71,11 +72,11 @@ def get_subfolders(path): return directories -def resolve_path(path:Union[str, Path], to:Union[str, Path]='.')-> Path: +def resolve_path(path: Union[str, Path], to: Union[str, Path] = '.') -> Path: """Resolve a path partly overlapping with to another path.""" pwd = Path(to).absolute() pwd = [p for p in pwd.parts] - ret = [p for p in Path(path).parts if p not in pwd] + ret = [p for p in Path(path).parts if p not in pwd] return Path('/'.join(ret)) @@ -144,8 +145,8 @@ def parse_dict(input_dict: dict, d = dict() for k, v in input_dict.items(): for (old_type, fct) in types: - if isinstance(v, old_type): - v = fct(v) + if isinstance(v, old_type): + v = fct(v) d[k] = v return d @@ -170,4 +171,4 @@ def extend_name(fname: Union[str, Path], extend_by: str, ext: str = None) -> Pat ext = fname.suffix fname = fname.parent / f"{fname.stem}{extend_by}" fname = fname.with_suffix(ext) - return fname \ No newline at end of file + return fname diff --git a/vaep/io/data_objects.py b/vaep/io/data_objects.py index 8ffb62340..62d81ac71 100644 --- a/vaep/io/data_objects.py +++ b/vaep/io/data_objects.py @@ -21,6 +21,8 @@ from vaep.plotting import plot_feat_counts # from .config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED +from fastcore.imports import IN_IPYTHON, IN_JUPYTER, IN_COLAB, IN_NOTEBOOK + logger = logging.getLogger(__name__) logger.info(f"Calling from {__name__}") @@ -39,7 +41,6 @@ DEFAULTS.COUNT_ALL_PEPTIDES = FOLDER_PROCESSED / 'count_all_peptides.json' # fastcore.imports has in_notebook, etc functionality -from fastcore.imports import IN_IPYTHON, IN_JUPYTER, IN_COLAB, IN_NOTEBOOK # IN_IPYTHON,IN_JUPYTER,IN_COLAB,IN_NOTEBOOK = in_ipython(),in_jupyter(),in_colab(),in_notebook() N_WORKERS_DEFAULT = os.cpu_count() - 1 if os.cpu_count() <= 16 else 16 @@ -172,6 +173,8 @@ def get_files_w_min_MS2(self, threshold=10_000, relativ_to=FOLDER_MQ_TXT_DATA): return [Path(relativ_to) / folder for folder in self.df.loc[mask].index] # maybe move functions related to fnames + + def get_fname(N, M): """Helper function to get file for intensities""" return f'df_intensities_N{N:05d}_M{M:05d}' @@ -185,8 +188,7 @@ def create_parent_folder_name(folder: Path) -> str: return folder.stem[:4] -## plotting function for value_counts from FeatureCounter.get_df_counts - +# plotting function for value_counts from FeatureCounter.get_df_counts def collect_in_chuncks(paths: Iterable[Union[str, Path]], @@ -196,7 +198,7 @@ def collect_in_chuncks(paths: Iterable[Union[str, Path]], desc='Run chunks in parallel') -> List: """collect the results from process_chunk_fct (chunk of files to loop over). The idea is that process_chunk_fct creates a more memory-efficient intermediate - result than possible if only callling single fpaths in paths. + result than possible if only callling single fpaths in paths. Parameters ---------- @@ -216,8 +218,8 @@ def collect_in_chuncks(paths: Iterable[Union[str, Path]], if n_workers > 1: with multiprocessing.Pool(n_workers) as p: collected = list(tqdm(p.imap(process_chunk_fct, paths_splits), - total=len(paths_splits), - desc=desc)) + total=len(paths_splits), + desc=desc)) else: collected = map(process_chunk_fct, paths_splits) return collected @@ -225,9 +227,9 @@ def collect_in_chuncks(paths: Iterable[Union[str, Path]], class FeatureCounter(): def __init__(self, fp_counter: str, counting_fct: Callable[[List], Counter], - idx_names:Union[List, None]=None, - feature_name='feature', - overwrite=False): + idx_names: Union[List, None] = None, + feature_name='feature', + overwrite=False): self.fp = Path(fp_counter) self.counting_fct = counting_fct self.idx_names = idx_names @@ -238,7 +240,7 @@ def __init__(self, fp_counter: str, counting_fct: Callable[[List], Counter], self.loaded = set(folder for folder in d['based_on']) self.dumps = d['dumps'] else: - self.loaded = set() # None + self.loaded = set() # None self.counter = Counter() self.dumps = dict() @@ -262,10 +264,10 @@ def sum_over_files(self, folders: List[Path], n_workers=N_WORKERS_DEFAULT, save= if folders: list_of_sample_dicts = collect_in_chuncks(folders, - process_chunk_fct=self.counting_fct, - n_workers = n_workers, - chunks=n_workers*3, - desc = 'Count features in 100 chunks') + process_chunk_fct=self.counting_fct, + n_workers=n_workers, + chunks=n_workers * 3, + desc='Count features in 100 chunks') for d in tqdm(list_of_sample_dicts, total=len(list_of_sample_dicts), @@ -286,7 +288,6 @@ def sum_over_files(self, folders: List[Path], n_workers=N_WORKERS_DEFAULT, save= @property def n_samples(self): return len(self.loaded) - def get_df_counts(self) -> pd.DataFrame: """Counted features as DataFrame with proportion values. @@ -297,14 +298,14 @@ def get_df_counts(self) -> pd.DataFrame: _description_ """ feat_counts = (pd.Series(self.counter) - .sort_values(ascending=False) - .to_frame('counts')) + .sort_values(ascending=False) + .to_frame('counts')) feat_counts['proportion'] = feat_counts / self.n_samples - if self.idx_names: + if self.idx_names: feat_counts.index.names = self.idx_names feat_counts.reset_index(inplace=True) feat_counts.index.name = 'consecutive count' - return feat_counts + return feat_counts def plot_counts(self, df_counts: pd.DataFrame = None, ax=None, prop_feat=0.25, min_feat_prop=.01): """Plot counts based on get_df_counts.""" @@ -348,8 +349,8 @@ def save(self): } """ d = {'counter': self.counter, - 'based_on': list(self.loaded), - 'dumps': {k: str(v) for k, v in self.dumps.items()}} + 'based_on': list(self.loaded), + 'dumps': {k: str(v) for k, v in self.dumps.items()}} logger.info(f"Save to: {self.fp}") dump_json(d, filename=self.fp) @@ -357,7 +358,7 @@ def load(self, fp): with open(self.fp) as f: d = json.load(f) d['counter'] = Counter(d['counter']) - d['dumps'] = {k: Path(v) for k,v in d['dumps'].items()} + d['dumps'] = {k: Path(v) for k, v in d['dumps'].items()} return d def load_dump(self, fpath, fct=pd.read_csv, use_cols=None): @@ -392,11 +393,12 @@ def __call__(self, folders, c.update(df.index) if self.dump: fpath_dict[folder.stem] = dump_to_csv(df, folder=folder, outfolder=self.outfolder, - parent_folder_fct=self.parent_folder_fct) + parent_folder_fct=self.parent_folder_fct) ret = {'counter': c, 'dumps': fpath_dict} return ret -### aggregated peptides +# aggregated peptides + # # check df for redundant information (same feature value for all entries) usecols = mq.COLS_ + ['Potential contaminant', mq.mq_col.SEQUENCE, 'PEP'] @@ -418,11 +420,12 @@ def count_peptides(folders: List[Path], dump=True, c.update(peptides.index) if dump: fpath_dict[folder.stem] = dump_to_csv(peptides.drop('Potential contaminant', axis=1), - folder=folder, outfolder=outfolder, - parent_folder_fct=parent_folder_fct) + folder=folder, outfolder=outfolder, + parent_folder_fct=parent_folder_fct) ret = {'counter': c, 'dumps': fpath_dict} return ret + d_dtypes_training_sample = { 'Sequence': pd.StringDtype(), 'Proteins': pd.StringDtype(), @@ -438,6 +441,7 @@ def load_agg_peptide_dump(fpath): peptides = pd.read_csv(fpath, index_col=0, dtype=d_dtypes_training_sample) return peptides + @delegates() class PeptideCounter(FeatureCounter): @@ -446,7 +450,7 @@ def __init__(self, counting_fct: Callable[[List], Counter] = count_peptides, idx_names=['Sequence'], feature_name='aggregated peptide', - **kwargs): + **kwargs): super().__init__(fp_counter, counting_fct=counting_fct, idx_names=idx_names, feature_name=feature_name, **kwargs) @@ -455,8 +459,7 @@ def load_dump(fpath): return load_agg_peptide_dump(fpath) - -### Evidence +# Evidence evidence_cols = mq.mq_evidence_cols @@ -504,7 +507,7 @@ def count_evidence(folders: List[Path], c.update(evidence.index) if dump: fpath_dict[folder.stem] = dump_to_csv(evidence, folder=folder, outfolder=outfolder, - parent_folder_fct=parent_folder_fct) + parent_folder_fct=parent_folder_fct) ret = {'counter': c, 'dumps': fpath_dict} return ret @@ -530,7 +533,7 @@ def save(self): } """ d = {'counter': vaep.pandas.create_dict_of_dicts(self.counter), - 'based_on': list(self.loaded), + 'based_on': list(self.loaded), 'dumps': {k: str(v) for k, v in self.dumps.items()}} print(f"Save to: {self.fp}") dump_json(d, filename=self.fp) @@ -540,7 +543,7 @@ def load(self, fp): d = json.load(f) d['counter'] = Counter( vaep.pandas.flatten_dict_of_dicts(d['counter'])) - d['dumps'] = {k: Path(v) for k,v in d['dumps'].items()} + d['dumps'] = {k: Path(v) for k, v in d['dumps'].items()} return d @@ -548,7 +551,7 @@ def load_evidence_dump(fpath, index_col=['Sequence', 'Charge']): df = pd.read_csv(fpath, index_col=index_col) return df -### Protein Groups +# Protein Groups pg_cols = mq.mq_protein_groups_cols @@ -557,7 +560,7 @@ def load_evidence_dump(fpath, index_col=['Sequence', 'Charge']): def load_and_process_proteinGroups(folder: Union[str, Path], - #use_cols not really a parameter (or needs asserts?) + # use_cols not really a parameter (or needs asserts?) use_cols: List = [ pg_cols.Protein_IDs, pg_cols.Majority_protein_IDs, @@ -580,7 +583,7 @@ def load_and_process_proteinGroups(folder: Union[str, Path], pg = pg.loc[mask] gene_set = pg[pg_cols.Gene_names].str.split(';') col_loc_gene_names = pg.columns.get_loc(pg_cols.Gene_names) - _ = pg.insert(col_loc_gene_names+1, 'Number of Genes', + _ = pg.insert(col_loc_gene_names + 1, 'Number of Genes', gene_set.apply(vaep.pandas.length)) mask_no_gene = pg[pg_cols.Gene_names].isna() pg_no_gene = pg.loc[mask_no_gene] @@ -593,9 +596,6 @@ def load_and_process_proteinGroups(folder: Union[str, Path], return pg - - - count_protein_groups = Count(load_and_process_proteinGroups, use_cols=[ pg_cols.Protein_IDs, @@ -619,7 +619,7 @@ class ProteinGroupsCounter(FeatureCounter): def __init__(self, fp_counter: str, counting_fct: Callable[[List], Counter] = count_protein_groups, - idx_names=[pg_cols.Protein_IDs], # mq_specfic + idx_names=[pg_cols.Protein_IDs], # mq_specfic feature_name='protein group', **kwargs): super().__init__(fp_counter, counting_fct, idx_names=idx_names, @@ -631,9 +631,10 @@ def load_pg_dump(folder, use_cols=None): df = pd.read_csv(folder, index_col=pg_cols.Protein_IDs, usecols=use_cols) return df -## Gene Counter +# Gene Counter + -def pg_idx_gene_fct(folder:Union[str, Path], use_cols=None): +def pg_idx_gene_fct(folder: Union[str, Path], use_cols=None): folder = Path(folder) logger.debug(f"Load: {folder}") df = pd.read_csv(folder, index_col=pg_cols.Gene_names, usecols=use_cols) @@ -650,7 +651,7 @@ def pg_idx_gene_fct(folder:Union[str, Path], use_cols=None): dump=False) -#summing needs to be done over processed proteinGroup dumps +# summing needs to be done over processed proteinGroup dumps @delegates() class GeneCounter(FeatureCounter): """Gene Counter to count gene in dumped proteinGroups.""" diff --git a/vaep/io/dataloaders.py b/vaep/io/dataloaders.py index e98d2dd03..7443d28d6 100644 --- a/vaep/io/dataloaders.py +++ b/vaep/io/dataloaders.py @@ -33,7 +33,7 @@ def __init__(self, scaler : [type] A pipeline of transform to apply to the dataset. DataSetClass : torch.utils.data.Dataset - Type of dataset to use for generating single samples based on + Type of dataset to use for generating single samples based on DataFrames. batch_size : int Batch size to use. @@ -49,7 +49,10 @@ def __init__(self, self.scaler = scaler self.batch_size = batch_size - def get_dls(self, shuffle_train: bool = True, **kwargs) -> Tuple[torch.utils.data.DataLoader, torch.utils.data.DataLoader]: + def get_dls(self, + shuffle_train: bool = True, + **kwargs) -> Tuple[torch.utils.data.DataLoader, + torch.utils.data.DataLoader]: self.shuffle_train = shuffle_train dl_train = DataLoader( dataset=self.data_train, @@ -106,7 +109,7 @@ def get_dls(train_X: pandas.DataFrame, transforms = VaepPipeline(df_train=train_X, encode=dae_default_pipeline, decode=['normalize']) - dls = get_dls(train_X, val_X, transforms, bs=4) + dls = get_dls(train_X, val_X, transforms, bs=4) """ train_ds = datasets.DatasetWithTarget(df=train_X, transformer=transformer) diff --git a/vaep/io/datasets.py b/vaep/io/datasets.py index 9f854e1ce..53839626d 100644 --- a/vaep/io/datasets.py +++ b/vaep/io/datasets.py @@ -9,6 +9,7 @@ DEFAULT_DTYPE = torch.get_default_dtype() + class PeptideDatasetInMemory(Dataset): """Peptide Dataset fully in memory.""" @@ -23,7 +24,7 @@ def __init__(self, data: np.array, mask: np.array = None, fill_na=0.0): Peptide data for training, potentially with missings. mask : [type], optional Mask selecting values for evaluation from data(y), by default None - If no mask is provided, all non-missing values from `data`-array + If no mask is provided, all non-missing values from `data`-array will be used. fill_na : int, optional value to replace missing values with, by default 0 @@ -83,19 +84,21 @@ def __getitem__(self, idx) -> Tuple[torch.Tensor, torch.Tensor]: mask_isna = self.mask_isna.iloc[idx] data = self.data.iloc[idx] mask_isna, data = to_tensor(mask_isna), to_tensor(data) - return mask_isna, data + return mask_isna, data + class DatasetWithTarget(DatasetWithMaskAndNoTarget): def __getitem__(self, idx) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: mask, data = super().__getitem__(idx) - return mask, data, data + return mask, data, data + class DatasetWithTargetSpecifyTarget(DatasetWithMaskAndNoTarget): - def __init__(self, df: pd.DataFrame, targets:pd.DataFrame, + def __init__(self, df: pd.DataFrame, targets: pd.DataFrame, transformer: sklearn.pipeline.Pipeline = None): - """Create a dataset for validation. + """Create a dataset for validation. Parameters ---------- @@ -113,7 +116,7 @@ def __init__(self, df: pd.DataFrame, targets:pd.DataFrame, self.columns = df.columns self.transformer = transformer - self.target = df.fillna(targets) # not really necessary, without mask would not be needed + self.target = df.fillna(targets) # not really necessary, without mask would not be needed if transformer: if hasattr(transformer, 'transform'): @@ -125,16 +128,16 @@ def __init__(self, df: pd.DataFrame, targets:pd.DataFrame, self.data = df self.length_ = len(self.data) - def __getitem__(self, idx) -> Tuple[torch.Tensor, torch.Tensor]: - mask_isna, data = super().__getitem__(idx) - target = to_tensor(self.target.iloc[idx]) + mask_isna, data = super().__getitem__(idx) + target = to_tensor(self.target.iloc[idx]) return mask_isna, data, target + class PeptideDatasetInMemoryMasked(DatasetWithMaskAndNoTarget): """Peptide Dataset fully in memory. - + Dataset: torch.utils.data.Dataset """ @@ -155,7 +158,7 @@ def __init__(self, *args, fill_na=0, **kwargs): class PeptideDatasetInMemoryNoMissings(Dataset): """Peptide Dataset fully in memory. - + Dataset: torch.utils.data.Dataset """ diff --git a/vaep/io/datasplits.py b/vaep/io/datasplits.py index a6de3ace5..daae63bc2 100644 --- a/vaep/io/datasplits.py +++ b/vaep/io/datasplits.py @@ -17,6 +17,7 @@ # 'pickle': 'to_pickle', 'csv': ('to_csv', 'read_csv')} + def long_format(df: pd.DataFrame, colname_values: str = 'intensity', # index_name: str = 'Sample ID' @@ -49,7 +50,6 @@ class DataSplits(): train_X: pd.DataFrame = None val_y: pd.DataFrame = None test_y: pd.DataFrame = None - def __post_init__(self): self._items = sorted(self.__dict__) @@ -64,12 +64,12 @@ def __dir__(self): return ['dump', 'from_folder', 'interpolate', 'load', 'test_X', 'test_y', 'to_long_format', 'to_wide_format', 'train_X', 'val_X', 'val_y'] - def dump(self, folder='data', file_format='csv')-> dict: + def dump(self, folder='data', file_format='csv') -> dict: """dump in long format.""" folder = Path(folder) folder.mkdir(parents=True, exist_ok=True) - if not file_format in FILE_FORMAT_TO_DUMP_FCT: + if file_format not in FILE_FORMAT_TO_DUMP_FCT: raise ValueError(f"Select one of these formats: {', '.join(FILE_FORMAT_TO_DUMP_FCT.keys())}") dumps = {} n_dumped = 0 @@ -128,11 +128,11 @@ def to_wide_format(self): _df = _series.unstack() setattr(self, _attr, _df) self._is_wide = True - - def to_long_format(self, name_values:str='intensity'): - if not self._is_wide: + + def to_long_format(self, name_values: str = 'intensity'): + if not self._is_wide: return - + for _attr, _df in self: if _df is None: continue @@ -142,7 +142,7 @@ def to_long_format(self, name_values:str='intensity'): self._is_wide = False # singledispatch possible - def interpolate(self, dataset:Union[str, pd.DataFrame]): + def interpolate(self, dataset: Union[str, pd.DataFrame]): if issubclass(type(dataset), pd.DataFrame): ds = dataset elif issubclass(type(dataset), pd.Series): @@ -152,7 +152,7 @@ def interpolate(self, dataset:Union[str, pd.DataFrame]): ds = getattr(self, dataset) except AttributeError: raise AttributeError(f"Please provide a valid attribute, not '{dataset}'. " - "Valid attributes are {}".format(', '.join(x for x in self._items))) + "Valid attributes are {}".format(', '.join(x for x in self._items))) if dataset[-1] in ['y', 'Y']: logger.warning( f'Attempting to interpolate target: {dataset} ' @@ -160,15 +160,13 @@ def interpolate(self, dataset:Union[str, pd.DataFrame]): if ds is None: raise ValueError(f'Attribute is None: {dataset!r}.') if not self._is_wide: - ds = ds.unstack() # series is unstack to DataFrame + ds = ds.unstack() # series is unstack to DataFrame else: raise TypeError(f"Unknown type: {classname(dataset)}." - f" None of str, {class_full_module(pd.DataFrame)}, {class_full_module(pd.Series)}" - ) - - return interpolate(wide_df=ds) - + f" None of str, {class_full_module(pd.DataFrame)}, {class_full_module(pd.Series)}" + ) + return interpolate(wide_df=ds) def load_items(folder: str, items: dict, use_wide_format=False, file_format='csv') -> dict: @@ -184,7 +182,8 @@ def load_items(folder: str, items: dict, use_wide_format=False, file_format='csv read_fct = getattr(pd, FILE_FORMAT_TO_DUMP_FCT[file_format][1]) _df = read_fct(fname) # logic below is suited for csv reader -> maybe split up loading and saving later? - if len(_df.shape) == 1: _df = _df.to_frame().reset_index() # in case Series was pickled + if len(_df.shape) == 1: + _df = _df.to_frame().reset_index() # in case Series was pickled cols = list(_df.columns) if use_wide_format: _df = wide_format(_df.set_index(cols[1:-1]), columns=cols[0], name_values=cols[-1]) @@ -196,7 +195,7 @@ def load_items(folder: str, items: dict, use_wide_format=False, file_format='csv # set default file name -> intergrate into DataSplits? -def load_freq(folder:str, file='freq_features.pkl'): +def load_freq(folder: str, file='freq_features.pkl'): folder = Path(folder) fname = folder / file if fname.suffix == '.json': @@ -206,4 +205,4 @@ def load_freq(folder:str, file='freq_features.pkl'): freq_per_feature = pd.read_pickle(fname) else: raise ValueError(f"Unknown Fileextension: {fname.suffix}") - return freq_per_feature \ No newline at end of file + return freq_per_feature diff --git a/vaep/io/filenames.py b/vaep/io/filenames.py index ee9c122fa..d6338e6d7 100644 --- a/vaep/io/filenames.py +++ b/vaep/io/filenames.py @@ -4,11 +4,13 @@ logger = logging.getLogger(__name__) -def read_number_from_str(fname:str, regex:str='M[0-9]*', strip:int=1) -> int: + +def read_number_from_str(fname: str, regex: str = 'M[0-9]*', strip: int = 1) -> int: M = re.search(regex, fname).group() logger.info(f"Found: {M}") M = int(M[strip:]) return M + read_M_features = functools.partial(read_number_from_str, regex='M[0-9]*', strip=1) read_N_samples = functools.partial(read_number_from_str, regex='N[0-9]*', strip=1) diff --git a/vaep/io/format.py b/vaep/io/format.py index f316f8b5f..8ac18df95 100644 --- a/vaep/io/format.py +++ b/vaep/io/format.py @@ -11,7 +11,7 @@ def classname(obj): """ Return entire object's class name (repr notation) as str. Source: https://gist.github.com/clbarnes/edd28ea32010eb159b34b075687bb49e - + Parameters ---------- obj : object diff --git a/vaep/io/mq.py b/vaep/io/mq.py index daa843b0e..3bae23ff1 100644 --- a/vaep/io/mq.py +++ b/vaep/io/mq.py @@ -210,10 +210,10 @@ class MaxQuantOutput(): Attributes ---------- - self.files : list + self.files : list list of files in `folder`. _inital_attritubutes : list - Initial set of non-magic attributes + Initial set of non-magic attributes NAME_FILE_MAP : dict Keys for known MaxQuant output files. """ @@ -319,7 +319,7 @@ class MaxQuantOutputDynamic(MaxQuantOutput): name_file_map : dict Keys for known MaxQuant output files. _inital_attritubutes : list - Initial set of non-magic attributes + Initial set of non-magic attributes """ def __init__(self, folder): @@ -368,7 +368,7 @@ def check_df(df, columns): missing = [] for col in columns: - if not col in df: + if col not in df: missing.append(col) if missing: @@ -380,7 +380,7 @@ def check_df(df, columns): def get_peptides_with_single_gene(peptides, keep_columns=COLS_, gene_column=mq_col.GENE_NAMES): """Get long-data-format. Ungroup gene names. Peptides "shared" by genes - are assigned individual rows. retains only cases with full list of + are assigned individual rows. retains only cases with full list of features provided by `keep_columns`. Parameters @@ -388,7 +388,7 @@ def get_peptides_with_single_gene(peptides, keep_columns=COLS_, gene_column=mq_c peptides: pandas.DataFrame MaxQuant txt output loaded as `pandas.DataFrame`. keep_columns: list - List of columns to keep from the `peptides`.txt, default + List of columns to keep from the `peptides`.txt, default {cols_} gene_column: str Column containing group information of format "group1;group2", @@ -474,7 +474,7 @@ def count_genes_in_sets(gene_sets, sep=';'): def get_identifier_from_column(df: pd.DataFrame, identifier_col: str): - """Get unique identifier in a column of a DataFrame. + """Get unique identifier in a column of a DataFrame. Parameters ---------- @@ -579,7 +579,7 @@ def find_exact_cleaved_peptides_for_razor_protein(gene_data, fasta_db, gene_id: # pendants (e.g. Keratin: Q04695;CON__Q04695) # exclude potential other contaminents protein_sets = [ - x for x in proteins_shared_by_all if not 'CON__' in x] # .sorted() + x for x in proteins_shared_by_all if 'CON__' not in x] # .sorted() if len(protein_sets) == 0: # raise KeyError("No other overall protein found for sequences.") logger.warning( @@ -606,7 +606,7 @@ def calculate_completness_for_sample( peps_exact_cleaved : Iterable[str] Iterable of peptides exactly cleaved peps_in_data : Iterable[str] - Iterable of peptides found during a run / in a sample. Check if peptides + Iterable of peptides found during a run / in a sample. Check if peptides overlap with any of the exact peptides. Returns diff --git a/vaep/io/rawfiles.py b/vaep/io/rawfiles.py index 7fd0b897b..04df932cf 100644 --- a/vaep/io/rawfiles.py +++ b/vaep/io/rawfiles.py @@ -18,7 +18,7 @@ def find_indices_containing_query(query, X): def get_unique_stem(query, index: pd.Index): """Gets stem filename, by splitting filename left of query and remove last underscore _. - + Fractionated samples seem to be named by fraction type. Last field indicates fraction. """ ret = index.str.split(query).str[0].str.rsplit("_", n=1).str[0] @@ -34,7 +34,7 @@ def show_fractions(stub: str, df): class RawFileViewer: - def __init__(self, df:pd.DataFrame, start_query: str="[Ff]rac", outputfolder: str='.', path_col='path'): + def __init__(self, df: pd.DataFrame, start_query: str = "[Ff]rac", outputfolder: str = '.', path_col='path'): """Indices are used.""" self.df = df self.file_names = df.index @@ -42,7 +42,7 @@ def __init__(self, df:pd.DataFrame, start_query: str="[Ff]rac", outputfolder: st self.w_query = widgets.Text(start_query) self.query = start_query - + self.save_button = widgets.Button(description='Save current files.') self.save_button.on_click(self.save_current_files) @@ -59,10 +59,10 @@ def get_options(self, query): sub_df = self.find_indices_containing_query(query) ret = get_unique_stem(query, sub_df.index) return ret - except: + except BaseException: print(f"Not a valid query: {query} ") return () - + def save_current_files(self, button): """Save files in current views as txt file. """ @@ -74,12 +74,12 @@ def save_current_files(self, button): with open(fname, 'w') as f: f.write(f'-lmkdir {self.stub}\n') for _path in files: - _local_path = PurePosixPath(self.stub)/_path.name + _local_path = PurePosixPath(self.stub) / _path.name _remote_path = PurePosixPath(_path) line = line_template.format(remote_path=_remote_path, local_path=_local_path) f.write(f'{line}\n') print(f"Saved file paths to: {fname}") - + def viewer(self, query, stub: str): if query != self.query: self.query = query @@ -91,7 +91,7 @@ def viewer(self, query, stub: str): print(f"Nothing to display for QUERY: {query}") stub = None # find_indices_containing_query = partial(find_indices_containing_query, X=data_unique) - if stub and stub!=self.stub: + if stub and stub != self.stub: try: subset = self.df[self.df.index.str.contains(stub)] print('current stub: ', repr(stub)) diff --git a/vaep/io/thermo_raw_files.py b/vaep/io/thermo_raw_files.py index 2238d5afc..4bebfb58a 100644 --- a/vaep/io/thermo_raw_files.py +++ b/vaep/io/thermo_raw_files.py @@ -23,4 +23,3 @@ 'injection volume setting', 'dilution factor', ] - diff --git a/vaep/io/types.py b/vaep/io/types.py index b738d04a7..5f807113a 100644 --- a/vaep/io/types.py +++ b/vaep/io/types.py @@ -1,7 +1,9 @@ """ papermill strategy to determine type -see: https://github.com/nteract/papermill/blob/76906a882bb5b3e719ad113c7b2447e0ddffb2c7/papermill/cli.py#L275-L307 +see: https://github.com/nteract/papermill/blob/76906a882bb5b3e719ad113c7b2447e0ddffb2c7/papermill/cli.py#L275-L307 """ + + def resolve_type(value): if value == "True": return True @@ -34,4 +36,4 @@ def _is_float(value): except ValueError: return False else: - return True \ No newline at end of file + return True diff --git a/vaep/model.py b/vaep/model.py index 6d0e39c24..74e947643 100644 --- a/vaep/model.py +++ b/vaep/model.py @@ -13,17 +13,6 @@ logger = logging.getLogger(__name__) - - - - - - - - - - - def build_df_from_pred_batches(pred, scaler=None, index=None, columns=None): pred = np.vstack(pred) if scaler: @@ -32,10 +21,10 @@ def build_df_from_pred_batches(pred, scaler=None, index=None, columns=None): return pred -def get_latent_space(model_method_call:callable, - dl:torch.utils.data.DataLoader, - dl_index:pd.Index, - latent_tuple_pos:int=0) -> pd.DataFrame: +def get_latent_space(model_method_call: callable, + dl: torch.utils.data.DataLoader, + dl_index: pd.Index, + latent_tuple_pos: int = 0) -> pd.DataFrame: """Create a DataFrame of the latent space based on the model method call to be used (here: the model encoder or a latent space helper method) @@ -60,7 +49,7 @@ def get_latent_space(model_method_call:callable, for b in dl: model_input = b[1] res = model_method_call(model_input) - #if issubclass(type(res), torch.Tensor): + # if issubclass(type(res), torch.Tensor): if isinstance(res, tuple): res = res[latent_tuple_pos] res = res.detach().numpy() @@ -74,8 +63,6 @@ def get_latent_space(model_method_call:callable, return latent_space - - # # Defining the model manuelly # import torch.nn as nn diff --git a/vaep/models/__init__.py b/vaep/models/__init__.py index 55ac20670..c3c34de02 100644 --- a/vaep/models/__init__.py +++ b/vaep/models/__init__.py @@ -10,7 +10,7 @@ import matplotlib.pyplot as plt import numpy as np import pandas as pd -import torch +import torch from fastcore.foundation import L from fastai import learner import sklearn.metrics as sklm @@ -26,8 +26,8 @@ def plot_loss(recorder: learner.Recorder, - norm_train:np.int64=np.int64(1), - norm_val:np.int64=np.int64(1), + norm_train: np.int64 = np.int64(1), + norm_val: np.int64 = np.int64(1), skip_start: int = 5, with_valid: bool = True, ax: plt.Axes = None) -> plt.Axes: @@ -39,9 +39,9 @@ def plot_loss(recorder: learner.Recorder, recorder : learner.Recorder fastai Recorder object, learn.recorder norm_train: np.int64, optional - Normalize epoch loss by number of training samples, by default 1 + Normalize epoch loss by number of training samples, by default 1 norm_val: np.int64, optional - Normalize epoch loss by number of validation samples, by default 1 + Normalize epoch loss by number of validation samples, by default 1 skip_start : int, optional Skip N first batch metrics, by default 5 with_valid : bool, optional @@ -61,7 +61,7 @@ def plot_loss(recorder: learner.Recorder, if with_valid: idx = (np.array(recorder.iters) < skip_start).sum() ax.plot(recorder.iters[idx:], L( - recorder.values[idx:]).itemgot(1) / norm_val , label='valid') + recorder.values[idx:]).itemgot(1) / norm_val, label='valid') ax.legend() return ax @@ -70,7 +70,7 @@ def plot_training_losses(learner: learner.Learner, name: str, ax=None, save_recorder: bool = True, - norm_factors = np.array([1,1], dtype='int'), + norm_factors=np.array([1, 1], dtype='int'), folder='figures', figsize=(15, 8)): if ax is None: @@ -96,6 +96,7 @@ def calc_net_weight_count(model: torch.nn.modules.module.Module) -> int: weight_count += np.prod(param.size()) return int(weight_count) + class RecorderDump: """Simple Class to hold fastai Recorder Callback data for serialization using pickle. """ @@ -120,8 +121,6 @@ def load(cls, filepath, name): plot_loss = plot_loss - - def split_prediction_by_mask(pred: pd.DataFrame, mask: pd.DataFrame, check_keeps_all: bool = False) -> Tuple[pd.DataFrame, pd.DataFrame]: @@ -152,17 +151,17 @@ def split_prediction_by_mask(pred: pd.DataFrame, def compare_indices(first_index: pd.Index, second_index: pd.Index) -> pd.Index: """Show difference of indices in other index wrt. to first. First should be the larger collection wrt to the second. This is the set difference of two Index objects. - + If second index is a superset of indices of the first, the set will be empty, although there are differences (default behaviour in pandas). - + Parameters ---------- first_index : pd.Index Index, should be superset second_index : pd.Index Index, should be the subset - + Returns ------- pd.Index @@ -181,8 +180,7 @@ def compare_indices(first_index: pd.Index, second_index: pd.Index) -> pd.Index: ('MAE', sklm.mean_absolute_error)] - -def collect_metrics(metrics_jsons:List, key_fct: Callable) -> dict: +def collect_metrics(metrics_jsons: List, key_fct: Callable) -> dict: """Collect and aggregate a bunch of json metrics. Parameters @@ -207,7 +205,7 @@ def collect_metrics(metrics_jsons:List, key_fct: Callable) -> dict: fname = Path(fname) logger.info(f"Load file: {fname = }") - key = key_fct(fname) # level, repeat + key = key_fct(fname) # level, repeat logger.debug(f"{key = }") with open(fname) as f: diff --git a/vaep/models/ae.py b/vaep/models/ae.py index 29cc99dff..1c59157a2 100644 --- a/vaep/models/ae.py +++ b/vaep/models/ae.py @@ -28,8 +28,6 @@ logger = logging.getLogger(__name__) - - def get_preds_from_df(df: pd.DataFrame, learn: fastai.learner.Learner, transformer: vaep.transform.VaepPipeline, @@ -60,7 +58,7 @@ def get_preds_from_df(df: pd.DataFrame, dl = vaep.io.dataloaders.get_test_dl(df=df, transformer=transformer, dataset=dataset) - res = learn.get_preds(dl=dl) # -> dl could be int + res = learn.get_preds(dl=dl) # -> dl could be int if position_pred_tuple is not None and issubclass(type(res[0]), tuple): res = (res[0][position_pred_tuple], *res[1:]) res = L(res).map(lambda x: pd.DataFrame( @@ -69,9 +67,9 @@ def get_preds_from_df(df: pd.DataFrame, return res - leaky_relu_default = nn.LeakyReLU(.1) + class Autoencoder(nn.Module): """Autoencoder base class. @@ -116,8 +114,8 @@ def build_layer(in_feat, out_feat): # Encoder self.encoder = [] - for i in range(len(self.layers)-1): - in_feat, out_feat = self.layers[i:i+2] + for i in range(len(self.layers) - 1): + in_feat, out_feat = self.layers[i:i + 2] self.encoder.extend(build_layer(in_feat=in_feat, out_feat=out_feat)) self.encoder.append(nn.Linear(out_feat, dim_latent)) @@ -133,11 +131,11 @@ def build_layer(in_feat, out_feat): out_feat=out_feat) i = -1 # in case a single hidden layer is passed - for i in range(len(self.layers_decoder)-2): - in_feat, out_feat = self.layers_decoder[i:i+2] + for i in range(len(self.layers_decoder) - 2): + in_feat, out_feat = self.layers_decoder[i:i + 2] self.decoder.extend(build_layer(in_feat=in_feat, out_feat=out_feat)) - in_feat, out_feat = self.layers_decoder[i+1:i+3] + in_feat, out_feat = self.layers_decoder[i + 1:i + 3] self.decoder.append(nn.Linear(in_feat, out_feat)) if last_decoder_activation is not None: @@ -159,7 +157,7 @@ def get_missing_values(df_train_wide: pd.DataFrame, Parameters ---------- df_train_wide : pd.DataFrame - Training data in wide format. + Training data in wide format. val_idx : pd.Index Indices (MultiIndex of Sample and Feature) of validation split test_idx : pd.Index @@ -170,7 +168,7 @@ def get_missing_values(df_train_wide: pd.DataFrame, Returns ------- pd.Series - Multiindex series of missing values in training data which are not + Multiindex series of missing values in training data which are not in validiation and test split. """ # all idx missing in training data @@ -215,7 +213,7 @@ def get_missing_values(df_train_wide: pd.DataFrame, # assert self.layers_decoder is not self.layers # assert out_feat == self.layers_decoder[0] # self.decoder = [nn.Linear(self.dim_latent, out_feat), -# activation(), +# activation(), # nn.BatchNorm1d(out_feat)] # for i in range(len(self.layers_decoder)-1): # in_feat, out_feat = self.layers_decoder[i:i+2] @@ -278,9 +276,9 @@ def after_pred(self): class ModelAdapterFlatPred(DatasetWithTargetAdapter): - """Models forward only expects on input matrix. + """Models forward only expects on input matrix. Apply mask from dataloader to both pred and targets. - + Return only predictions and target for non NA inputs. """ @@ -302,9 +300,9 @@ def after_pred(self): class ModelAdapter(ModelAdapterFlatPred): - """Models forward only expects on input matrix. + """Models forward only expects on input matrix. Apply mask from dataloader to both pred and targets. - + Keep original dimension, i.e. also predictions for NA.""" def after_pred(self): @@ -321,7 +319,7 @@ def after_loss(self): class ModelAdapterVAEFlat(DatasetWithTargetAdapter): - """Models forward method only expects one input matrix. + """Models forward method only expects one input matrix. Apply mask from dataloader to both pred and targets.""" def before_batch(self): @@ -336,7 +334,7 @@ def after_pred(self): pred, mu, logvar = self.pred # return predictions self.learn.pred = (pred[self._mask], mu, logvar) # is this flat? elif len(self.pred) == 4: - x_mu,x_logvar, z_mu, z_logvar = self.pred + x_mu, x_logvar, z_mu, z_logvar = self.pred self.learn.pred = (x_mu[self._mask], x_logvar[self._mask], z_mu, z_logvar) # same as ModelAdapter. Inheritence is limiting composition here @@ -356,43 +354,39 @@ def after_loss(self): self.learn.yb = (self._all_y,) - - - class AutoEncoderAnalysis(analysis.ModelAnalysis): def __init__(self, - train_df:pd.DataFrame, - val_df:pd.DataFrame, # values to use for validation - model:torch.nn.modules.module.Module, - model_kwargs:dict, + train_df: pd.DataFrame, + val_df: pd.DataFrame, # values to use for validation + model: torch.nn.modules.module.Module, + model_kwargs: dict, transform: sklearn.pipeline.Pipeline, decode: List[str], bs=64 ): - self.transform = vaep.transform.VaepPipeline( - df_train=train_df, - encode=transform, - decode=decode) + self.transform = vaep.transform.VaepPipeline( + df_train=train_df, + encode=transform, + decode=decode) self.dls = vaep.io.dataloaders.get_dls( - train_X=train_df, - valid_X=val_df, - transformer=self.transform, bs=bs) + train_X=train_df, + valid_X=val_df, + transformer=self.transform, bs=bs) # M = data.train_X.shape[-1] self.kwargs_model = model_kwargs self.params = dict(self.kwargs_model) self.model = model(**self.kwargs_model) - + self.n_params_ae = vaep.models.calc_net_weight_count(self.model) self.params['n_parameters'] = self.n_params_ae self.learn = None - - def get_preds_from_df(self, df_wide:pd.DataFrame) -> pd.DataFrame: - if self.learn is None: raise ValueError("Assign Learner first as learn attribute.") - return get_preds_from_df(df=df_wide, learn=self.learn, transformer=self.transform) - - def get_test_dl(self, df_wide:pd.DataFrame, bs:int=64) -> pd.DataFrame: - return vaep.io.dataloaders.get_test_dl(df=df_wide, transformer=self.transform, bs=bs) + def get_preds_from_df(self, df_wide: pd.DataFrame) -> pd.DataFrame: + if self.learn is None: + raise ValueError("Assign Learner first as learn attribute.") + return get_preds_from_df(df=df_wide, learn=self.learn, transformer=self.transform) + def get_test_dl(self, df_wide: pd.DataFrame, bs: int = 64) -> pd.DataFrame: + return vaep.io.dataloaders.get_test_dl(df=df_wide, transformer=self.transform, bs=bs) diff --git a/vaep/models/analysis.py b/vaep/models/analysis.py index d0d6a1dbf..93d8a2aaa 100644 --- a/vaep/models/analysis.py +++ b/vaep/models/analysis.py @@ -5,11 +5,12 @@ from vaep.analyzers import Analysis + class ModelAnalysis(Analysis): """Class describing what an ModelAnalysis is supposed to have as attributes.""" model: torch.nn.Module dls: fastai.data.core.DataLoaders - learn: fastai.learner.Learner + learn: fastai.learner.Learner params: dict - transform: vaep.transform.VaepPipeline \ No newline at end of file + transform: vaep.transform.VaepPipeline diff --git a/vaep/models/cmd.py b/vaep/models/cmd.py index c0893401a..c31003c61 100644 --- a/vaep/models/cmd.py +++ b/vaep/models/cmd.py @@ -30,16 +30,16 @@ def create_argparser(): BATCH_SIZE = 16 EPOCHS = 600 + def get_args(batch_size=BATCH_SIZE, epochs=EPOCHS, log_interval=10, no_cuda=False): """Helper function to create arg.""" - args = ['--batch-size', str(batch_size), - '--seed', '43', - '--epochs', str(epochs), + args = ['--batch-size', str(batch_size), + '--seed', '43', + '--epochs', str(epochs), '--log-interval', str(log_interval)] if no_cuda: args.append('--no-cuda') args = parser.parse_args(args) args.cuda = torch.cuda.is_available() and not args.no_cuda return args - diff --git a/vaep/models/collab.py b/vaep/models/collab.py index 3d045a26c..bb37a9b46 100644 --- a/vaep/models/collab.py +++ b/vaep/models/collab.py @@ -38,7 +38,7 @@ def forward(self, x): def combine_data(train_df: pd.DataFrame, val_df: pd.DataFrame) -> Tuple[pd.DataFrame, float]: - """Helper function to combine training and validation data in long-format. The + """Helper function to combine training and validation data in long-format. The training and validation data will be mixed up in CF training as the sample embeddings have to be trained for all samples. The returned frac can be used to have the same number of (non-missing) validation samples as before. @@ -57,7 +57,7 @@ def combine_data(train_df: pd.DataFrame, val_df: pd.DataFrame) -> Tuple[pd.DataF Fraction of samples originally in validation data. """ X = train_df.append(val_df).reset_index() - frac = len(val_df) / (len(train_df)+len(val_df)) + frac = len(val_df) / (len(train_df) + len(val_df)) return X, frac @@ -100,7 +100,7 @@ def collab_dot_product(sample_embeddings: torch.tensor, sample_bias: torch.tenso res = res.detach() if y_range is None: return res - return torch.sigmoid(res) * (y_range[1]-y_range[0]) + y_range[0] + return torch.sigmoid(res) * (y_range[1] - y_range[0]) + y_range[0] def collab_prediction(idx_samples: torch.tensor, @@ -112,20 +112,20 @@ def collab_prediction(idx_samples: torch.tensor, Parameters ---------- idx_samples : torch.tensor - An array containing the neighreast neighbors in the training data for + An array containing the neighreast neighbors in the training data for set of list of test samples. Normallay obtained from a sklearn KNN search. learn : fastai.learner.Learner The learner used for collab training index_samples : pd.Index, optional The pandas.Index for the training samples. If no index_samples is provided, the samples will just be numbered, - by default None + by default None Returns ------- pd.DataFrame predictions as DataFrame for all features encoded by the model for all samples. - + """ # Matrix multiplication way test_sample_embeddings = learn.u_weight( @@ -141,7 +141,7 @@ def collab_prediction(idx_samples: torch.tensor, res = res + feat_biases.T + test_sample_biases if learn.y_range is not None: - res = torch.sigmoid(res) * (learn.y_range[1]-learn.y_range[0] + res = torch.sigmoid(res) * (learn.y_range[1] - learn.y_range[0] ) + learn.y_range[0] res = pd.DataFrame(res, @@ -162,7 +162,7 @@ def __init__(self, batch_size=64): if datasplits.val_y is not None: self.X, self.frac = combine_data(datasplits.train_X, - datasplits.val_y) + datasplits.val_y) else: self.X, self.frac = datasplits.train_X.reset_index(), 0.0 self.batch_size = batch_size @@ -172,16 +172,23 @@ def __init__(self, item_name=item_column, rating_name=target_column, bs=self.batch_size) - user_name=sample_column - item_name=item_column - rating_name=target_column - cat_names = [user_name,item_name] + user_name = sample_column + item_name = item_column + rating_name = target_column + cat_names = [user_name, item_name] ratings = self.X splits = None if datasplits.val_y is not None: - idx_splitter = IndexSplitter(list(range(len(datasplits.train_X), len(datasplits.train_X)+ len(datasplits.val_y) ))) + idx_splitter = IndexSplitter( + list(range(len(datasplits.train_X), len(datasplits.train_X) + len(datasplits.val_y)))) splits = idx_splitter(self.X) - to = TabularCollab(ratings, [Categorify], cat_names, y_names=[rating_name], y_block=TransformBlock(), splits=splits) + to = TabularCollab( + ratings, + [Categorify], + cat_names, + y_names=[rating_name], + y_block=TransformBlock(), + splits=splits) self.dls = to.dataloaders(path='.', bs=self.batch_size) self.params = {} self.model_kwargs = model_kwargs diff --git a/vaep/models/collect_dumps.py b/vaep/models/collect_dumps.py index 1854bd8f2..d0359ac22 100644 --- a/vaep/models/collect_dumps.py +++ b/vaep/models/collect_dumps.py @@ -55,4 +55,4 @@ def collect(paths: Iterable, collect_configs = partial(collect, load_fn=load_config_file, ) -collect_configs = update_wrapper(collect_configs, collect) \ No newline at end of file +collect_configs = update_wrapper(collect_configs, collect) diff --git a/vaep/models/vae.py b/vaep/models/vae.py index e7e2e8401..6395773e7 100644 --- a/vaep/models/vae.py +++ b/vaep/models/vae.py @@ -15,6 +15,7 @@ leaky_relu_default = nn.LeakyReLU(.1) + class VAE(nn.Module): def __init__(self, n_features: int, @@ -39,11 +40,11 @@ def build_layer(in_feat, out_feat): # Encoder self.encoder = [] - for i in range(len(self.layers)-1): - in_feat, out_feat = self.layers[i:i+2] + for i in range(len(self.layers) - 1): + in_feat, out_feat = self.layers[i:i + 2] self.encoder.extend(build_layer(in_feat=in_feat, out_feat=out_feat)) - self.encoder.append(nn.Linear(out_feat, dim_latent*2)) + self.encoder.append(nn.Linear(out_feat, dim_latent * 2)) self.encoder = nn.Sequential(*self.encoder) @@ -56,13 +57,13 @@ def build_layer(in_feat, out_feat): out_feat=out_feat) i = -1 # in case a single hidden layer is passed - for i in range(len(self.layers_decoder)-2): - in_feat, out_feat = self.layers_decoder[i:i+2] + for i in range(len(self.layers_decoder) - 2): + in_feat, out_feat = self.layers_decoder[i:i + 2] self.decoder.extend(build_layer(in_feat=in_feat, out_feat=out_feat)) - in_feat, out_feat = self.layers_decoder[i+1:i+3] + in_feat, out_feat = self.layers_decoder[i + 1:i + 3] - self.decoder.append(nn.Linear(in_feat, out_feat*2)) + self.decoder.append(nn.Linear(in_feat, out_feat * 2)) if last_decoder_activation is not None: self.append(last_decoder_activation) @@ -84,7 +85,7 @@ def decode(self, z): return x_mu, x_logvar def reparameterize(self, mu, logvar): - std = torch.exp(0.5*logvar) + std = torch.exp(0.5 * logvar) return mu + torch.randn_like(std) * std def forward(self, x): @@ -95,11 +96,11 @@ def forward(self, x): def compute_kld(z_mu, z_logvar): - return 0.5*(z_mu**2 + torch.exp(z_logvar) - 1 - z_logvar) + return 0.5 * (z_mu**2 + torch.exp(z_logvar) - 1 - z_logvar) def gaussian_log_prob(z, mu, logvar): - return -0.5*(math.log(2*math.pi) + logvar + (z-mu)**2/torch.exp(logvar)) + return -0.5 * (math.log(2 * math.pi) + logvar + (z - mu)**2 / torch.exp(logvar)) def loss_fct(pred, y, reduction='sum', results: List = None, freebits=0.1): @@ -108,7 +109,7 @@ def loss_fct(pred, y, reduction='sum', results: List = None, freebits=0.1): l_rec = -torch.sum(gaussian_log_prob(batch, x_mu, x_logvar)) l_reg = torch.sum(F.relu(compute_kld(z_mu, z_logvar) - - freebits*math.log(2))+freebits*math.log(2), 1) + freebits * math.log(2)) + freebits * math.log(2), 1) if results is not None: results.append((l_rec.item(), torch.mean(l_reg).item())) diff --git a/vaep/nb.py b/vaep/nb.py index a8a4246e7..0d13104b7 100644 --- a/vaep/nb.py +++ b/vaep/nb.py @@ -9,14 +9,15 @@ class Config(): - """Config class with a setter enforcing that config entries cannot + """Config class with a setter enforcing that config entries cannot be overwritten. Can contain configs, which are itself configs: keys, paths, - + """ + def __setattr__(self, entry, value): """Set if attribute not in instance.""" if hasattr(self, entry) and getattr(self, entry) != value: @@ -45,7 +46,7 @@ def dump(self, fname=None): logger.info(f"Dumped config to: {fname}") @classmethod - def from_dict(cls, d:dict): + def from_dict(cls, d: dict): cfg = cls() for k, v in d.items(): setattr(cfg, k, v) @@ -57,17 +58,18 @@ def update_from_dict(self, params: dict): setattr(self, k, v) except AttributeError: logger.info(f"Already set attribute: {k} has value {v}") - + def keys(self): return vars(self).keys() def items(self): return vars(self).items() - + def values(self): return vars(self).values() -def get_params(args:dict.keys, globals, remove=True) -> dict: + +def get_params(args: dict.keys, globals, remove=True) -> dict: params = {k: v for k, v in globals.items() if k not in args and k[0] != '_'} if not remove: return params diff --git a/vaep/pandas/__init__.py b/vaep/pandas/__init__.py index bdbfa97f3..b10ce763a 100644 --- a/vaep/pandas/__init__.py +++ b/vaep/pandas/__init__.py @@ -12,6 +12,7 @@ from .calc_errors import calc_errors_per_feat, get_absolute_error + def combine_value_counts(X: pd.DataFrame, dropna=True) -> pd.DataFrame: """Pass a selection of columns to combine it's value counts. @@ -40,9 +41,9 @@ def combine_value_counts(X: pd.DataFrame, dropna=True) -> pd.DataFrame: def counts_with_proportion(s: pd.Series) -> pd.DataFrame: - """Counts with proportion of counts(!). - - Note: In case of missing values the proportion is not based on the total number of + """Counts with proportion of counts(!). + + Note: In case of missing values the proportion is not based on the total number of rows in the DataFrame. """ s = s.value_counts() @@ -111,11 +112,13 @@ def replace_with(string_key: str, replace: str = "()/", replace_with: str = '') string_key = string_key.replace(symbol, replace_with) return string_key -def index_to_dict(index:pd.Index) -> dict: + +def index_to_dict(index: pd.Index) -> dict: cols = {replace_with(col.replace(' ', '_').replace( '-', '_')): col for col in index} return cols + def get_columns_accessor(df: pd.DataFrame, all_lower_case=False) -> omegaconf.OmegaConf: if isinstance(df.columns, pd.MultiIndex): raise ValueError("MultiIndex not supported.") @@ -132,6 +135,7 @@ def get_columns_accessor_from_iterable(cols: Iterable[str], cols = {k.lower(): v for k, v in cols.items()} return omegaconf.OmegaConf.create(cols) + def select_max_by(df: pd.DataFrame, grouping_columns: list, selection_column: str) -> pd.DataFrame: df = df.sort_values(by=[*grouping_columns, selection_column], ascending=False) df = df.drop_duplicates(subset=grouping_columns, @@ -189,7 +193,7 @@ def _add_indices(array: np.array, original_df: pd.DataFrame, def interpolate(wide_df: pd.DataFrame, name='interpolated') -> pd.DataFrame: """Interpolate NA values with the values before and after. Uses n=3 replicates. - First rows replicates are the two following. + First rows replicates are the two following. Last rows replicates are the two preceding. Parameters @@ -219,7 +223,7 @@ def interpolate(wide_df: pd.DataFrame, name='interpolated') -> pd.DataFrame: ret.iloc[0] = first_row ret.iloc[-1] = last_row - ret = ret[mask].stack().dropna().squeeze() # does not work with MultiIndex columns + ret = ret[mask].stack().dropna().squeeze() # does not work with MultiIndex columns ret.rename(name, inplace=True) return ret @@ -236,7 +240,7 @@ def create_dict_of_dicts(d: dict, verbose=False, print(f"current key: {str(keys):90}: {len(v):>5}") current_dict = ret for k in keys[:-1]: - if not k in current_dict: + if k not in current_dict: current_dict[k] = dict() current_dict = current_dict[k] last_key = keys[-1] @@ -319,13 +323,13 @@ def length(x): Otherwise return length of list, pandas.Series, numpy.array, dict, etc.""" try: return len(x) - except: + except BaseException: return 0 def get_last_index_matching_proportion(df_counts: pd.DataFrame, - prop:float=0.25, - prop_col:str='proportion') -> object: + prop: float = 0.25, + prop_col: str = 'proportion') -> object: """df_counts needs to be sorted by "prop_col" (descending). Parameters @@ -349,8 +353,8 @@ def get_last_index_matching_proportion(df_counts: pd.DataFrame, return idx_cutoff -def get_lower_whiskers(df:pd.DataFrame, factor:float=1.5) -> pd.Series: +def get_lower_whiskers(df: pd.DataFrame, factor: float = 1.5) -> pd.Series: ret = df.describe() iqr = ret.loc['75%'] - ret.loc['25%'] - ret = ret.loc['25%'] - iqr*factor - return ret \ No newline at end of file + ret = ret.loc['25%'] - iqr * factor + return ret diff --git a/vaep/pandas/missing_data.py b/vaep/pandas/missing_data.py index b810895e5..7bd62e0ae 100644 --- a/vaep/pandas/missing_data.py +++ b/vaep/pandas/missing_data.py @@ -4,12 +4,15 @@ import pandas as pd + def percent_missing(df: pd.DataFrame) -> float: return df.isna().sum().sum() / math.prod(df.shape) + def percent_non_missing(df: pd.DataFrame) -> float: return df.notna().sum().sum() / math.prod(df.shape) + def list_files(folder='.') -> list[str]: return [f.as_posix() for f in Path(folder).iterdir()] @@ -29,4 +32,3 @@ def get_record(data: pd.DataFrame, columns_sample=False) -> dict: N_mis=int(N_mis), missing=float(missing), ) return record - diff --git a/vaep/plotting/__init__.py b/vaep/plotting/__init__.py index ebbb8def2..a1fab486a 100644 --- a/vaep/plotting/__init__.py +++ b/vaep/plotting/__init__.py @@ -1,4 +1,5 @@ from __future__ import annotations + import numpy as np import pandas as pd import matplotlib @@ -9,22 +10,22 @@ import vaep.pandas +from .errors import plot_rolling_error +from . import errors +from . import data +from . import plotly +from . defaults import order_categories, labels_dict, IDX_ORDER + seaborn.set_style("whitegrid") # seaborn.set_theme() -plt.rcParams['figure.figsize'] = [16.0, 7.0] # [4, 2], [4, 3] +plt.rcParams['figure.figsize'] = [16.0, 7.0] # [4, 2], [4, 3] plt.rcParams['pdf.fonttype'] = 42 plt.rcParams['ps.fonttype'] = 42 plt.rcParams['figure.dpi'] = 147 -from . defaults import order_categories, labels_dict, IDX_ORDER -from . import plotly -from . import data -from . import errors -from .errors import plot_rolling_error - logger = logging.getLogger(__name__) __all__ = ['plotly', @@ -40,6 +41,7 @@ 'plot_cutoffs', ] + def _savefig(fig, name, folder: pathlib.Path = '.', pdf=True, dpi=300 # default 'figure' @@ -107,9 +109,9 @@ def select_dates(date_series: pd.Series, max_ticks=30) -> np.array: def make_large_descriptors(size='xx-large'): - """Helper function to have very large titles, labes and tick texts for + """Helper function to have very large titles, labes and tick texts for matplotlib plots per default. - + size: str fontsize or allowed category. Change default if necessary, default 'xx-large' """ @@ -141,13 +143,13 @@ def add_prop_as_second_yaxis(ax: matplotlib.axes.Axes, n_samples: int, ax2 = ax.twinx() n_min, n_max = np.round(ax.get_ybound()) logger.info(f"{n_min = }, {n_max = }") - lower_prop = n_min/n_samples + (ax.get_ybound()[0] - n_min) / n_samples - upper_prop = n_max/n_samples + (ax.get_ybound()[1] - n_max) / n_samples + lower_prop = n_min / n_samples + (ax.get_ybound()[0] - n_min) / n_samples + upper_prop = n_max / n_samples + (ax.get_ybound()[1] - n_max) / n_samples logger.info(f'{lower_prop = }, {upper_prop = }') ax2.set_ybound(lower_prop, upper_prop) # _ = ax2.set_yticks(np.linspace(n_min/n_samples, # n_max /n_samples, len(ax.get_yticks())-2)) - _ = ax2.set_yticks(ax.get_yticks()[1:-1]/n_samples) + _ = ax2.set_yticks(ax.get_yticks()[1:-1] / n_samples) ax2.yaxis.set_major_formatter( matplotlib.ticker.StrMethodFormatter(format_str)) return ax2 @@ -160,7 +162,7 @@ def add_height_to_barplot(ax, size=5): ax.annotate(text=format(bar.get_height(), '.2f'), xy=(bar.get_x() + bar.get_width() / 2, bar.get_height()), - xytext=(0, int(size/2)), + xytext=(0, int(size / 2)), ha='center', va='center', size=size, @@ -208,7 +210,7 @@ def format_large_numbers(ax: matplotlib.axes.Axes, return ax -def plot_feat_counts(df_counts:pd.DataFrame, feat_name:str, n_samples:int, +def plot_feat_counts(df_counts: pd.DataFrame, feat_name: str, n_samples: int, ax=None, figsize=(15, 10), count_col='counts', **kwargs): @@ -218,7 +220,7 @@ def plot_feat_counts(df_counts:pd.DataFrame, feat_name:str, n_samples:int, title=f'Count and proportion of {len(df_counts):,d} {feat_name}s over {n_samples:,d} samples', ) args.update(kwargs) - + ax = df_counts[count_col].plot( figsize=figsize, @@ -236,8 +238,8 @@ def plot_feat_counts(df_counts:pd.DataFrame, feat_name:str, n_samples:int, def plot_counts(df_counts: pd.DataFrame, n_samples, - feat_col_name:str='count', - feature_name=None, + feat_col_name: str = 'count', + feature_name=None, ax=None, prop_feat=0.25, min_feat_prop=.01, **kwargs): """Plot counts based on get_df_counts.""" @@ -251,7 +253,7 @@ def plot_counts(df_counts: pd.DataFrame, n_samples, ax=ax, **kwargs) df_counts['prop'] = df_counts[feat_col_name] / n_samples n_feat_cutoff = vaep.pandas.get_last_index_matching_proportion( - df_counts=df_counts, prop=prop_feat, prop_col='prop') + df_counts=df_counts, prop=prop_feat, prop_col='prop') n_samples_cutoff = df_counts.loc[n_feat_cutoff, feat_col_name] logger.info(f'{n_feat_cutoff = }, {n_samples_cutoff = }') x_lim_max = vaep.pandas.get_last_index_matching_proportion( @@ -307,5 +309,3 @@ def plot_cutoffs(df: pd.DataFrame, if min_feat_in_sample is not None: ax.axhline(min_feat_in_sample) return fig, axes - - diff --git a/vaep/sampling.py b/vaep/sampling.py index a5c5f5f29..9716c14f1 100644 --- a/vaep/sampling.py +++ b/vaep/sampling.py @@ -16,11 +16,11 @@ def feature_frequency(df_wide: pd.DataFrame, measure_name: str = 'freq') -> pd.S Returns ------- pd.Series - Frequency on non-missing entries per feature (column). + Frequency on non-missing entries per feature (column). """ # if hasattr(df_wide.columns, "levels"): # is columns.names always set? # is listed as attribute: https://pandas.pydata.org/docs/reference/api/pandas.Index.html - _df_feat = df_wide.stack(df_wide.columns.names) # ensure that columns are named + _df_feat = df_wide.stack(df_wide.columns.names) # ensure that columns are named _df_feat = _df_feat.to_frame(measure_name) # implicit as stack puts column index in the last position (here: 1) @@ -61,8 +61,8 @@ def sample_data(series: pd.Series, sample_index_to_drop: Union[str, int], Parameters ---------- series : pd.Series - Long-format data in pd.Series. Index name is feature name. 2 dimensional - MultiIndex. + Long-format data in pd.Series. Index name is feature name. 2 dimensional + MultiIndex. sample_index_to_drop : Union[str, int] Sample index (as str or integer Index position). Unit to group by (i.e. Samples) frac : float, optional diff --git a/vaep/stats/__init__.py b/vaep/stats/__init__.py index 37992dbc5..3b7233754 100644 --- a/vaep/stats/__init__.py +++ b/vaep/stats/__init__.py @@ -1 +1 @@ -from . import diff_analysis \ No newline at end of file +from . import diff_analysis diff --git a/vaep/stats/diff_analysis.py b/vaep/stats/diff_analysis.py index d5ca991d2..13f411693 100644 --- a/vaep/stats/diff_analysis.py +++ b/vaep/stats/diff_analysis.py @@ -11,11 +11,11 @@ def ancova_pg(df_long: pd.DataFrame, feat_col: str, dv: str, between: str, - covar: list[str]|str, + covar: list[str] | str, fdr=0.05) -> pd.DataFrame: """ Analysis of covariance (ANCOVA) using pg.ancova https://pingouin-stats.org/generated/pingouin.ancova.html - + Adds multiple hypothesis testing correction by Benjamini-Hochberg (qvalue, rejected) @@ -64,7 +64,7 @@ def ancova_pg(df_long: pd.DataFrame, scores['-Log10 pvalue'] = -np.log10(scores['p-unc']) scores = scores[scores.Source != 'Residual'] - #FDR correction + # FDR correction scores = add_fdr_scores(scores, random_seed=123) return scores @@ -83,7 +83,7 @@ def analyze(df_proteomics: pd.DataFrame, df_clinic: pd.DataFrame, target: str, covar: list[str], - value_name: str='intensity') -> pd.DataFrame: + value_name: str = 'intensity') -> pd.DataFrame: """apply ancova and multiple test correction. Parameters diff --git a/vaep/tests/io/test_data_objects.py b/vaep/tests/io/test_data_objects.py index b36acf491..78ffa67cf 100644 --- a/vaep/tests/io/test_data_objects.py +++ b/vaep/tests/io/test_data_objects.py @@ -24,7 +24,7 @@ expected = """ Sequence,Charge,m/z,Protein group IDs,Intensity,Score YYYIPQYK,2,569.2844,3745,147680000.0,83.801 -YYVTIIDAPGHR,3,468.91386,2873,8630000000.0,131.83 +YYVTIIDAPGHR,3,468.91386,2873,8630000000.0,131.83 YYVTIIDAPGHR,2,702.867151,2873,2458400000.0,70.028 YYVLNALK,2,492.28166,3521,147430000.0,58.687 """ diff --git a/vaep/tests/io/test_dataloaders.py b/vaep/tests/io/test_dataloaders.py index 67206bd8b..a801beeba 100644 --- a/vaep/tests/io/test_dataloaders.py +++ b/vaep/tests/io/test_dataloaders.py @@ -10,7 +10,7 @@ def test_get_dls(): N, M = 23, 11 X_train = create_random_df(N, M) - N_valid = int(N*0.3) + N_valid = int(N * 0.3) X_valid = create_random_df( N_valid, M, prop_na=.1, start_idx=len(X_train)) @@ -18,13 +18,11 @@ def test_get_dls(): [('normalize', StandardScaler()), ('impute', SimpleImputer(add_indicator=False))]) transforms = VaepPipeline(df_train=X_train, - encode=dae_default_pipeline, - decode=['normalize']) + encode=dae_default_pipeline, + decode=['normalize']) BS = 4 dls = get_dls(train_X=X_train, valid_X=X_valid, transformer=transforms, bs=BS) assert len(dls.train_ds) == N assert len(dls.valid_ds) == N batch = dls.one_batch() assert batch[0].shape == (BS, M) - - diff --git a/vaep/tests/io/test_dataset.py b/vaep/tests/io/test_dataset.py index ae9da5a40..7fc12d431 100644 --- a/vaep/tests/io/test_dataset.py +++ b/vaep/tests/io/test_dataset.py @@ -6,7 +6,8 @@ from vaep.io.datasets import DatasetWithMaskAndNoTarget -def test_DatasetWithMaskAndNoTarget(): + +def test_DatasetWithMaskAndNoTarget(): with pytest.raises(ValueError): DatasetWithMaskAndNoTarget(df=np.random.rand(10, 5)) @@ -14,4 +15,4 @@ def test_DatasetWithMaskAndNoTarget(): data = helpers.create_DataFrame() ds = DatasetWithMaskAndNoTarget(df=data) assert all(ds[-1][1] == torch.tensor([95, 96, 97, 98, 99], dtype=torch.int32)) - assert all(ds[-1][0] == torch.tensor([False, False, False, False, False])) \ No newline at end of file + assert all(ds[-1][0] == torch.tensor([False, False, False, False, False])) diff --git a/vaep/tests/io/test_datasplits.py b/vaep/tests/io/test_datasplits.py index acae6f5c7..d9a4ebde0 100644 --- a/vaep/tests/io/test_datasplits.py +++ b/vaep/tests/io/test_datasplits.py @@ -8,14 +8,14 @@ X = np.random.rand(N, M) df = (pd.DataFrame(X, - index=[f'sample_{i}' for i in range(N)], - columns=(f'feat_{i}' for i in range(M))) - .rename_axis('Sample ID') - .rename_axis('Feature Name', axis=1)) + index=[f'sample_{i}' for i in range(N)], + columns=(f'feat_{i}' for i in range(M))) + .rename_axis('Sample ID') + .rename_axis('Feature Name', axis=1)) -_splits = {'train_X': df.iloc[:int(N*0.6)], - 'val_y': df.iloc[int(N*0.6):int(N*0.8)], - 'test_y': df.iloc[int(N*0.8):]} +_splits = {'train_X': df.iloc[:int(N * 0.6)], + 'val_y': df.iloc[int(N * 0.6):int(N * 0.8)], + 'test_y': df.iloc[int(N * 0.8):]} def test_DataSplits_iter(): @@ -54,11 +54,12 @@ def test_dump_load(tmp_path): splits = DataSplits(is_wide_format=None) splits.load(folder=tmp_path, use_wide_format=True) assert splits.train_X is not _splits['train_X'] - + npt.assert_almost_equal(_splits['train_X'].values, splits.train_X) # #ToDo: Index and Column names are not yet correctly set # assert splits.train_X.equals(_splits['train_X']) + def test_to_long_format(tmp_path): splits = DataSplits(**_splits, is_wide_format=True) splits.dump(folder=tmp_path) @@ -72,6 +73,7 @@ def test_to_long_format(tmp_path): assert splits.val_y is not expected assert splits.val_y.equals(expected) + def test_to_wide_format(tmp_path): splits = DataSplits(**_splits, is_wide_format=True) splits.dump(folder=tmp_path) @@ -85,9 +87,10 @@ def test_to_wide_format(tmp_path): assert splits.val_y is not expected assert splits.val_y.equals(expected) + def test_interpolate(): splits = DataSplits(**_splits, is_wide_format=True) - splits._is_wide = True # ToDo. Is not correctly set when init is called. + splits._is_wide = True # ToDo. Is not correctly set when init is called. with pytest.raises(AttributeError): _ = splits.interpolate('non-existing') diff --git a/vaep/tests/models/__pycache__/test_collect_dumps.py b/vaep/tests/models/__pycache__/test_collect_dumps.py index fd585f567..5dbc9b986 100644 --- a/vaep/tests/models/__pycache__/test_collect_dumps.py +++ b/vaep/tests/models/__pycache__/test_collect_dumps.py @@ -7,7 +7,3 @@ def test_select_content(): 'model_metrics_collab'] for test_case in test_cases: assert select_content(test_case, first_split='metrics_') == test_case.split('metrics_')[1] - - - - diff --git a/vaep/tests/pandas/test_calc_errors.py b/vaep/tests/pandas/test_calc_errors.py index c56e20bea..0749cd2d7 100644 --- a/vaep/tests/pandas/test_calc_errors.py +++ b/vaep/tests/pandas/test_calc_errors.py @@ -6,7 +6,7 @@ @fixture def example_data(): - """Example data with duplicated index values. Normally MulitIndex is used with + """Example data with duplicated index values. Normally MulitIndex is used with unique combination of sample and feat values.""" data = [[25.47317633, 27.23206642, 26.43510602, 28.40661375, 27.6536975], [30.57866718, 30.17035425, 30.22881888, 29.82725333, 30.1177242], @@ -21,7 +21,7 @@ def example_data(): data = pd.DataFrame(data, index=(f'feat_{i}' for i in [ 0, 0, 1, 1, 1, 2, 3, 4, 5, 6]), - columns=['observed'] + ['model_' + str(i+1) for i in range(4)]) + columns=['observed'] + ['model_' + str(i + 1) for i in range(4)]) data.columns.name = 'model' data.index.name = 'feat' data['freq_feat'] = [4, 5, 5, 4, 6, 7, 7, 9, 8, 6] diff --git a/vaep/tests/test_ae.py b/vaep/tests/test_ae.py index 1b30424f5..319f91e81 100644 --- a/vaep/tests/test_ae.py +++ b/vaep/tests/test_ae.py @@ -19,6 +19,7 @@ ) )""" + def test_basic_repr(): model = ae.Autoencoder(n_features=100, n_neurons=30) actual_repr = repr(model) @@ -26,6 +27,3 @@ def test_basic_repr(): assert model.dim_latent == 10 assert model.n_neurons == [30] assert model.n_features == 100 - - - diff --git a/vaep/tests/test_collab.py b/vaep/tests/test_collab.py index 42c4e4cc2..1e770d911 100644 --- a/vaep/tests/test_collab.py +++ b/vaep/tests/test_collab.py @@ -13,16 +13,17 @@ index=[f'sample_{i}' for i in range(N)], columns=(f'feat_{i}' for i in range(M))) -data = {'train_X': df.iloc[:int(N*0.6)], - 'val_y': df.iloc[int(N*0.6):int(N*0.8)], - 'test_y': df.iloc[int(N*0.8):]} +data = {'train_X': df.iloc[:int(N * 0.6)], + 'val_y': df.iloc[int(N * 0.6):int(N * 0.8)], + 'test_y': df.iloc[int(N * 0.8):]} data = DataSplits(**data, is_wide_format=True) -assert data._is_wide +assert data._is_wide data.to_long_format() + def test_combine_data(): N_train, N_val = len(data.train_X), len(data.val_y) X, frac = collab.combine_data(data.train_X, data.val_y) assert len(X) == N_train + N_val - npt.assert_almost_equal(frac, N_val / (N_train+N_val)) + npt.assert_almost_equal(frac, N_val / (N_train + N_val)) diff --git a/vaep/tests/test_helpers.py b/vaep/tests/test_helpers.py index d860bc319..fcde11887 100644 --- a/vaep/tests/test_helpers.py +++ b/vaep/tests/test_helpers.py @@ -3,9 +3,9 @@ from vaep.utils import create_random_missing_data + def test_create_random_missing_data(): data = create_random_missing_data(N=43, M=13, prop_missing=0.2) assert data.shape == (43, 13) assert np.isnan(data).sum() - assert abs((float(np.isnan(data).sum()) / (43 * 13) ) - 0.2 ) < 0.05 - + assert abs((float(np.isnan(data).sum()) / (43 * 13)) - 0.2) < 0.05 diff --git a/vaep/tests/test_imputation.py b/vaep/tests/test_imputation.py index 7419705c8..747b71c80 100644 --- a/vaep/tests/test_imputation.py +++ b/vaep/tests/test_imputation.py @@ -9,7 +9,7 @@ fraction_missing = proteins.notna().mean() -data = data[data.columns[fraction_missing > 0.4]] +data = data[data.columns[fraction_missing > 0.4]] N_FEAT = 200 N_FEAT_digits = len(str(N_FEAT)) data = data.sample(N_FEAT, axis=1) @@ -56,30 +56,29 @@ def test_imputation_normal_dist(): # def test_imputation_mixed_norm_KNN(): # pass + + @pytest.mark.parametrize('axis', [0, 1]) def test_impute_shifted_normal(example_data, axis): - mean_shift=1.8 - # remove zeros as these lead to -inf + mean_shift = 1.8 + # remove zeros as these lead to -inf example_data = np.log2(example_data.replace({0.0: np.nan}) - ).dropna(thresh=10, axis=1-axis) + ).dropna(thresh=10, axis=1 - axis) N, M = example_data.shape mask_observed = example_data.notna() imputed = impute_shifted_normal(example_data, axis=axis, mean_shift=mean_shift) - assert len(imputed) == ((N*M) - len(example_data.stack())) - + assert len(imputed) == ((N * M) - len(example_data.stack())) + if axis == 1: min_N = int(len(example_data) * 0.6) selected = example_data.dropna(axis=1, thresh=min_N) elif axis == 0: min_M = int(example_data.shape[1] * 0.6) selected = example_data.dropna(axis=0, thresh=min_M) - + mean = selected.mean(axis=axis) std = selected.std(axis=axis) mean_shifted = mean - (std * mean_shift) mean_imputed = imputed.unstack().mean(axis=axis) assert (mean_shifted - mean_imputed).abs().max() < 0.35 - - - diff --git a/vaep/tests/test_io.py b/vaep/tests/test_io.py index 610746a4c..143d705c5 100644 --- a/vaep/tests/test_io.py +++ b/vaep/tests/test_io.py @@ -3,16 +3,17 @@ import numpy as np import numpy.testing as npt -import vaep.io +import vaep.io from vaep.io.datasets import PeptideDatasetInMemory -data = np.random.random(size=(10,5)) +data = np.random.random(size=(10, 5)) mask = ~(data < 0.1) data_w_na = np.where(mask, data, np.nan) assert (data != data_w_na).any() assert (~np.isnan(data_w_na) == mask).all() + def test_PeptideDatasetInMemory_wo_Mask(): train_ds = PeptideDatasetInMemory(data_w_na, fill_na=0.0) mask_isna = np.isnan(data_w_na) @@ -25,8 +26,8 @@ def test_PeptideDatasetInMemory_wo_Mask(): def test_relative_to(): fpath = Path('project/runs/experiment_name/run') - pwd = 'project/runs/' # per defaut '.' (the current working directory) - expected = Path('experiment_name/run') + pwd = 'project/runs/' # per defaut '.' (the current working directory) + expected = Path('experiment_name/run') acutal = vaep.io.resolve_path(fpath, pwd) assert expected == acutal @@ -36,4 +37,4 @@ def test_relative_to(): # pwd = 'root/home/project/runs/' # per defaut '.' (the current working directory) # expected = Path('root/home/project/data/file') # acutal = vaep.io.resolve_path(fpath, pwd) - # assert expected == acutal \ No newline at end of file + # assert expected == acutal diff --git a/vaep/tests/test_nb.py b/vaep/tests/test_nb.py index 906406edb..a6dddb8b5 100644 --- a/vaep/tests/test_nb.py +++ b/vaep/tests/test_nb.py @@ -6,4 +6,4 @@ def test_Config(): cfg = Config() cfg.test = 'test' with pytest.raises(AttributeError): - cfg.test = 'raise AttributeError' \ No newline at end of file + cfg.test = 'raise AttributeError' diff --git a/vaep/tests/test_pandas.py b/vaep/tests/test_pandas.py index 555772594..7f66e1431 100644 --- a/vaep/tests/test_pandas.py +++ b/vaep/tests/test_pandas.py @@ -5,12 +5,12 @@ def test_interpolate(): test_data = { - "pep1": {0: nan, 1: 27.8, 2: 28.9, 3: nan, 4: 28.7}, - "pep2": {0: 29.1, 1: nan, 2: 27.6, 3: 29.1, 4: nan}, + "pep1": {0: nan, 1: 27.8, 2: 28.9, 3: nan, 4: 28.7}, + "pep2": {0: 29.1, 1: nan, 2: 27.6, 3: 29.1, 4: nan}, # 4 values replace based on one (edge case): - "pep3": {0: nan, 1: nan, 2: 23.6, 3: nan, 4: nan}, - "pep4": {0: nan, 1: nan, 2: nan, 3: nan, 4: nan}, - "pep5": {0: 26.0, 1: 27.0, 2: nan, 3: nan, 4: nan}, + "pep3": {0: nan, 1: nan, 2: 23.6, 3: nan, 4: nan}, + "pep4": {0: nan, 1: nan, 2: nan, 3: nan, 4: nan}, + "pep5": {0: 26.0, 1: 27.0, 2: nan, 3: nan, 4: nan}, } df_test_data = pd.DataFrame(test_data) @@ -52,11 +52,12 @@ def test_flatten_dict_of_dicts(): assert expected == actual + def test_create_dict_of_dicts(): data = {('a', 'a1', 'a2'): 1, - ('a', 'a1', 'a3'): 2, - ('b', 'b1', 'b2'): 3, - ('b', 'b1', 'b3'): 4} + ('a', 'a1', 'a3'): 2, + ('b', 'b1', 'b2'): 3, + ('b', 'b1', 'b3'): 4} expected = { "a": {'a1': {'a2': 1, 'a3': 2}}, "b": {'b1': {'b2': 3, 'b3': 4}} @@ -65,9 +66,9 @@ def test_create_dict_of_dicts(): assert expected == actual data = {('a', 'a1', 'a2'): (1, 1), - ('a', 'a1', 'a3'): (2, 2), - ('b', 'b1', 'b2'): (3, 3), - ('b', 'b1', 'b3'): (4, 4)} + ('a', 'a1', 'a3'): (2, 2), + ('b', 'b1', 'b2'): (3, 3), + ('b', 'b1', 'b3'): (4, 4)} expected = { "a": {'a1': {'a2': [1, 1], 'a3': [2, 2]}}, "b": {'b1': {'b2': [3, 3], 'b3': [4, 4]}} @@ -112,4 +113,4 @@ def test_key_map(): 'gamma': ('a', 'b'), 'delta': None}} actual = vaep.pandas.key_map(d) - assert expected == actual \ No newline at end of file + assert expected == actual diff --git a/vaep/tests/test_transfrom.py b/vaep/tests/test_transfrom.py index 0aa0176e8..2a1463580 100644 --- a/vaep/tests/test_transfrom.py +++ b/vaep/tests/test_transfrom.py @@ -4,7 +4,6 @@ import numpy.testing as npt - import sklearn from sklearn import preprocessing from sklearn import impute @@ -43,7 +42,7 @@ def test_Vaep_Pipeline(): dae_default_pipeline = sklearn.pipeline.Pipeline( [ ('normalize', preprocessing.StandardScaler()), - ('impute', impute.SimpleImputer(add_indicator=False)) # True won't work + ('impute', impute.SimpleImputer(add_indicator=False)) # True won't work ] ) from random_data import data @@ -52,20 +51,20 @@ def test_Vaep_Pipeline(): # new procs, transform equal encode, inverse_transform equals decode dae_transforms = VaepPipeline(df, encode=dae_default_pipeline) res = dae_transforms.transform(df) - assert type(res) == pd.DataFrame + assert isinstance(res, pd.DataFrame) with pytest.raises(ValueError): res = dae_transforms.inverse_transform(res) # pd.DataFrame - with pytest.raises(ValueError): + with pytest.raises(ValueError): _ = dae_transforms.inverse_transform(res.iloc[0]) # pd.DataFrame - with pytest.raises(ValueError): + with pytest.raises(ValueError): _ = dae_transforms.inverse_transform(res.loc['sample_156']) # pd.DataFrame - with pytest.raises(ValueError): + with pytest.raises(ValueError): _ = dae_transforms.inverse_transform(to_tensor(res)) # torch.Tensor - with pytest.raises(ValueError): + with pytest.raises(ValueError): _ = dae_transforms.inverse_transform(res.values) # numpy.array - with pytest.raises(ValueError): + with pytest.raises(ValueError): _ = dae_transforms.inverse_transform(res.values[0]) # single sample dae_transforms = VaepPipeline(df, encode=dae_default_pipeline, decode=['normalize']) res = dae_transforms.transform(df) res = dae_transforms.inverse_transform(res) - npt.assert_array_almost_equal(df.values[mask], res.values[mask]) \ No newline at end of file + npt.assert_array_almost_equal(df.values[mask], res.values[mask]) diff --git a/vaep/tf_board.py b/vaep/tf_board.py index 90f5b6ecf..bf8959e09 100644 --- a/vaep/tf_board.py +++ b/vaep/tf_board.py @@ -5,9 +5,10 @@ class TensorboardModelNamer(): """PyTorch SummaryWriter helper class for experiments. - + Creates new SummaryWriter for an experiment """ + def __init__(self, prefix_folder, root_dir=Path('runs')): """[summary] @@ -30,7 +31,7 @@ def get_model_name(self, hidden_layers: int, name = 'model_' name += f'hl{hidden_layers:02d}' - if type(neurons) == str: + if isinstance(neurons, str): neurons = neurons.split() elif not type(neurons) in [list, tuple]: raise TypeError( @@ -39,7 +40,7 @@ def get_model_name(self, hidden_layers: int, for x in neurons: name += f'_{x}' - if type(scaler) == str: + if isinstance(scaler, str): name += f'_{scaler}' else: name += f'_{scaler!r}' diff --git a/vaep/transform.py b/vaep/transform.py index ee3b9ac87..533599161 100644 --- a/vaep/transform.py +++ b/vaep/transform.py @@ -73,6 +73,7 @@ def inverse_transform(self, X, copy=None): # # arguments, see https://fastcore.fast.ai/meta.html#Metaprogramming # # decorate() + def transform(self, X, **kwargs): res = super(self.__class__, self).transform(X, **kwargs) if isinstance(X, pd.DataFrame): @@ -140,8 +141,9 @@ def get_df_fitted_mean_std(self, index): class VaepPipeline(): """Custom Pipeline combining a pandas.DataFrame and a sklearn.pipeline.Pipleine.""" - def __init__(self, df_train:pd.DataFrame, encode:sklearn.pipeline.Pipeline, - decode:List[str] =None): + + def __init__(self, df_train: pd.DataFrame, encode: sklearn.pipeline.Pipeline, + decode: List[str] = None): """[summary] Parameters @@ -153,7 +155,7 @@ def __init__(self, df_train:pd.DataFrame, encode:sklearn.pipeline.Pipeline, decode : List[str], optional subset of transforms (their string name) as an Iterable, by default None, i.e. the same as encode - """ + """ self.columns = df_train.columns self.M = len(df_train.columns) self.encode = encode @@ -163,20 +165,18 @@ def __init__(self, df_train:pd.DataFrame, encode:sklearn.pipeline.Pipeline, for d in decode: self.decode.append( (d, self.encode.named_steps[d]) - ) + ) self.decode = sklearn.pipeline.Pipeline(self.decode) else: self.decode = self.encode - - - + def transform(self, X): res = self.encode.transform(X) if isinstance(X, pd.DataFrame): return pd.DataFrame(res, columns=X.columns, index=X.index) return res - + # Option: single-dispatch based on type of X def inverse_transform(self, X, index=None): columns = self.columns @@ -195,4 +195,4 @@ def inverse_transform(self, X, index=None): X = X.reshape(-1, self.M) res = self.decode.inverse_transform(X) res = pd.DataFrame(res, columns=columns, index=index) - return res \ No newline at end of file + return res diff --git a/vaep/utils.py b/vaep/utils.py index 0ddccb131..d0ac0810e 100644 --- a/vaep/utils.py +++ b/vaep/utils.py @@ -19,8 +19,8 @@ def append_to_filepath(filepath: Union[pathlib.Path, str], to_append: str, sep: str = '_', new_suffix: str = None) -> pathlib.Path: - """Append filepath with specified to_append using a seperator. - + """Append filepath with specified to_append using a seperator. + Example: `data.csv` to data_processed.csv """ filepath = pathlib.Path(filepath) @@ -59,11 +59,11 @@ def create_long_df(N: int, M: int, prop_missing=0.1): def create_random_df(N: int, M: int, - scaling_factor: float = 30.0, - prop_na: float = 0.0, - start_idx: int = 0, - name_index='Sample ID', - name_columns='peptide'): + scaling_factor: float = 30.0, + prop_na: float = 0.0, + start_idx: int = 0, + name_index='Sample ID', + name_columns='peptide'): X = np.random.rand(N, M) if prop_na > 0.0 and prop_na < 1.0: @@ -74,7 +74,7 @@ def create_random_df(N: int, M: int, X = pd.DataFrame(X, index=[f'sample_{i:0{len(str(N))}}' - for i in range(start_idx, start_idx+N)], + for i in range(start_idx, start_idx + N)], columns=(f'feat_{i:0{len(str(M))}}' for i in range(M))) X.index.name = name_index X.columns.name = name_columns From 051711317dd8a98be5ca23a8beae8a64f020fdfa Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 19 Sep 2023 18:30:52 +0200 Subject: [PATCH 07/70] :sparkles: add further methods - msImpute - trKNN (from source) Add to workflow check. --- project/01_1_train_NAGuideR_methods.R | 28 ++++++++----- project/01_1_train_NAGuideR_methods.ipynb | 39 ++++++++++--------- .../single_dev_dataset/example/config.yaml | 2 + 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/project/01_1_train_NAGuideR_methods.R b/project/01_1_train_NAGuideR_methods.R index 0ef65fdc2..2b21d7e32 100644 --- a/project/01_1_train_NAGuideR_methods.R +++ b/project/01_1_train_NAGuideR_methods.R @@ -170,12 +170,14 @@ nafunctions <- function(x,method="zero"){ } else if(method=="trknn"){ source('src/R_NAGuideR/Imput_funcs.r') - sim_trKNN_wrapper <- function(data) { - result <- data %>% as.matrix %>% t %>% imputeKNN(., k=10, distance='truncation', perc=0) %>% t - return(result) - } - df1x <- sim_trKNN_wrapper(t(df1)) - df<-as.data.frame(t(df1x)) + # sim_trKNN_wrapper <- function(data) { + # result <- data %>% as.matrix %>% t %>% imputeKNN(., k=10, distance='truncation', perc=0) %>% t + # return(result) + # } + # df1x <- sim_trKNN_wrapper(t(df1)) + # df<-as.data.frame(t(df1x)) + df <- imputeKNN(as.matrix(df), k=10, distance='truncation', perc=0) + df <- as.data.frame(df) } else if(method=="rf"){ install_rpackage("missForest") @@ -212,10 +214,15 @@ nafunctions <- function(x,method="zero"){ df<-GMS.Lasso(df1,nfolds=3,log.scale=FALSE,TS.Lasso=TRUE) } + else if(method=="msimpute"){ + install_bioconductor("msImpute") + df <- msImpute(as.matrix(df), method='v2') + df <- as.data.frame(df) + } else{ stop(paste("Unspported methods so far: ", method)) } - df<-as.data.frame(df) + df <- as.data.frame(df) df } # - @@ -269,8 +276,8 @@ df original_header <- colnames( readr::read_csv(train_split, n_max=1, col_names=TRUE, skip=0) ) -original_header feat_name <- original_header[1] +original_header[1:5] # - # Uncomment to test certain methods (only for debugging, as at least one method per package is tested using Github Actions) @@ -298,7 +305,9 @@ feat_name <- original_header[1] # 'MICE-CART', # 'RF', # 'PI', - # 'GMS' # fails to install on Windows + # 'GMS', # fails to install on Windows + # 'trknn', + # 'msimpute' # ) # for (method in to_test) { @@ -316,7 +325,6 @@ pred <- tibble::as_tibble( ) names(pred) <- original_header pred - # + vscode={"languageId": "r"} pred <- reshape2::melt(pred, id.vars=feat_name) names(pred) <- c(feat_name, 'Sample ID', method) diff --git a/project/01_1_train_NAGuideR_methods.ipynb b/project/01_1_train_NAGuideR_methods.ipynb index 968614c11..41ed54001 100644 --- a/project/01_1_train_NAGuideR_methods.ipynb +++ b/project/01_1_train_NAGuideR_methods.ipynb @@ -1,7 +1,6 @@ { "cells": [ { - "attachments": {}, "cell_type": "markdown", "id": "afa6aadb-bb6e-4fa2-8c91-b69d6ff9af43", "metadata": {}, @@ -52,7 +51,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "edec29ae-208a-403a-aa77-82782bccba87", "metadata": {}, @@ -61,7 +59,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "c2e51b96-2f46-42c7-a642-a94c628dec04", "metadata": {}, @@ -198,12 +195,14 @@ " }\n", " else if(method==\"trknn\"){\n", " source('src/R_NAGuideR/Imput_funcs.r')\n", - " sim_trKNN_wrapper <- function(data) {\n", - " result <- data %>% as.matrix %>% t %>% imputeKNN(., k=10, distance='truncation', perc=0) %>% t\n", - " return(result)\n", - " }\n", - " df1x <- sim_trKNN_wrapper(t(df1))\n", - " df<-as.data.frame(t(df1x))\n", + " # sim_trKNN_wrapper <- function(data) {\n", + " # result <- data %>% as.matrix %>% t %>% imputeKNN(., k=10, distance='truncation', perc=0) %>% t\n", + " # return(result)\n", + " # }\n", + " # df1x <- sim_trKNN_wrapper(t(df1))\n", + " # df<-as.data.frame(t(df1x))\n", + " df <- imputeKNN(as.matrix(df), k=10, distance='truncation', perc=0)\n", + " df <- as.data.frame(df)\n", " }\n", " else if(method==\"rf\"){\n", " install_rpackage(\"missForest\")\n", @@ -240,16 +239,20 @@ " \n", " df<-GMS.Lasso(df1,nfolds=3,log.scale=FALSE,TS.Lasso=TRUE)\n", " }\n", + " else if(method==\"msimpute\"){\n", + " install_bioconductor(\"msImpute\")\n", + " df <- msImpute(as.matrix(df), method='v2')\n", + " df <- as.data.frame(df) \n", + " }\n", " else{\n", " stop(paste(\"Unspported methods so far: \", method))\n", " }\n", - " df<-as.data.frame(df)\n", + " df <- as.data.frame(df)\n", " df\n", " }" ] }, { - "attachments": {}, "cell_type": "markdown", "id": "7152239b-fad2-4e0f-8b3e-98d943cab264", "metadata": {}, @@ -303,7 +306,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "fc7ef882-0cbd-40f7-a77f-cc87f7145171", "metadata": {}, @@ -328,7 +330,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "3ed78a0c-2716-4629-bb15-8e3fd650576a", "metadata": { @@ -354,8 +355,8 @@ "original_header <- colnames(\n", " readr::read_csv(train_split, n_max=1, col_names=TRUE, skip=0)\n", ")\n", - "original_header\n", - "feat_name <- original_header[1]" + "feat_name <- original_header[1]\n", + "original_header[1:5]" ] }, { @@ -399,7 +400,9 @@ " # 'MICE-CART',\n", " # 'RF',\n", " # 'PI',\n", - " # 'GMS' # fails to install on Windows\n", + " # 'GMS', # fails to install on Windows\n", + " # 'trknn',\n", + " # 'msimpute'\n", "# )\n", "\n", "# for (method in to_test) {\n", @@ -409,7 +412,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "ff4ff1c2-192e-4a48-b5b6-d80ab989b12e", "metadata": {}, @@ -422,6 +424,7 @@ "execution_count": null, "id": "690d47c2-5666-41f2-b13f-9215334f197c", "metadata": { + "lines_to_next_cell": 0, "tags": [], "vscode": { "languageId": "r" @@ -514,7 +517,7 @@ "mimetype": "text/x-r-source", "name": "R", "pygments_lexer": "r", - "version": "3.6.3" + "version": "4.1.3" } }, "nbformat": 4, diff --git a/project/config/single_dev_dataset/example/config.yaml b/project/config/single_dev_dataset/example/config.yaml index 0181d36ed..4f32f8b2b 100644 --- a/project/config/single_dev_dataset/example/config.yaml +++ b/project/config/single_dev_dataset/example/config.yaml @@ -21,3 +21,5 @@ NAGuideR_methods: - MICE-NORM # mice - MLE # norm - IRM # VIM - ~9mins + - TRKNN + - MSIMPUTE From 25468d2a9a8b7a7d988e5b701d17e5973bcf871d Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 20 Sep 2023 13:49:05 +0200 Subject: [PATCH 08/70] :sparkles: group plots by seocndary nb number - start grouping output for an easier overview (than only alphabetical) --- project/01_0_split_data.ipynb | 60 ++--- project/01_0_split_data.py | 51 +++-- project/01_2_performance_plots.ipynb | 323 ++++++++++++++++++--------- project/01_2_performance_plots.py | 65 +++--- 4 files changed, 308 insertions(+), 191 deletions(-) diff --git a/project/01_0_split_data.ipynb b/project/01_0_split_data.ipynb index 7ec02d1d6..32cdb3713 100644 --- a/project/01_0_split_data.ipynb +++ b/project/01_0_split_data.ipynb @@ -80,6 +80,7 @@ "cell_type": "code", "execution_count": null, "metadata": { + "lines_to_next_cell": 2, "tags": [ "parameters" ] @@ -105,10 +106,7 @@ "meta_cat_col: str = None # category column in meta data\n", "# train, validation and test data splits\n", "frac_non_train: float = 0.1 # fraction of non training data (validation and test split)\n", - "frac_mnar: float = 0.0 # fraction of missing not at random data, rest: missing completely at random\n", - "\n", - "meta_date_col: str = 'Content Creation Date'\n", - "meta_cat_col: str = 'Software Version'" + "frac_mnar: float = 0.0 # fraction of missing not at random data, rest: missing completely at random" ] }, { @@ -183,7 +181,7 @@ "metadata": {}, "outputs": [], "source": [ - "! factor out file reading to a separate module, not class\n", + "# ! factor out file reading to a separate module, not class\n", "# AnalyzePeptides.from_csv\n", "constructor = getattr(AnalyzePeptides, FILE_FORMAT_TO_CONSTRUCTOR[FILE_EXT])\n", "analysis = constructor(fname=params.FN_INTENSITIES,\n", @@ -583,10 +581,11 @@ "metadata": {}, "outputs": [], "source": [ + "group = 1\n", "ax = df.notna().sum(axis=1).hist()\n", "ax.set_xlabel('features per eligable sample')\n", "ax.set_ylabel('observations')\n", - "fname = params.out_figures / 'hist_features_per_sample'\n", + "fname = params.out_figures / f'0_{group}_hist_features_per_sample'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), fname)" ] @@ -605,7 +604,7 @@ " horizontalalignment='right')\n", "ax.set_xlabel('feature prevalence')\n", "ax.set_ylabel('observations')\n", - "fname = params.out_figures / 'feature_prevalence'\n", + "fname = params.out_figures / f'0_{group}_feature_prevalence'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), fname)" ] @@ -627,7 +626,7 @@ "ax, bins = vaep.plotting.data.plot_histogram_intensities(\n", " df.stack(), min_max=min_max)\n", "\n", - "fname = params.out_figures / 'intensity_distribution_overall'\n", + "fname = params.out_figures / f'0_{group}_intensity_distribution_overall'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), fname)" ] @@ -640,7 +639,7 @@ "source": [ "ax = vaep.plotting.data.plot_feat_median_over_prop_missing(\n", " data=df, type='scatter')\n", - "fname = params.out_figures / 'intensity_median_vs_prop_missing_scatter'\n", + "fname = params.out_figures / f'0_{group}_intensity_median_vs_prop_missing_scatter'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), fname)" ] @@ -653,7 +652,7 @@ "source": [ "ax = vaep.plotting.data.plot_feat_median_over_prop_missing(\n", " data=df, type='boxplot')\n", - "fname = params.out_figures / 'intensity_median_vs_prop_missing_boxplot'\n", + "fname = params.out_figures / f'0_{group}_intensity_median_vs_prop_missing_boxplot'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), fname)" ] @@ -712,7 +711,7 @@ " analyzers.seaborn_scatter(\n", " pcs[pcs_name], ax, meta=pcs[params.meta_cat_col], title=f\"by {params.meta_cat_col}\")\n", " fname = (params.out_figures\n", - " / f'pca_sample_by_{\"_\".join(params.meta_cat_col.split())}')\n", + " / f'0_{group}_pca_sample_by_{\"_\".join(params.meta_cat_col.split())}')\n", " figures[fname.stem] = fname\n", " vaep.savefig(fig, fname)" ] @@ -727,7 +726,7 @@ " fig, ax = plt.subplots()\n", " analyzers.plot_date_map(\n", " df=pcs[pcs_name], ax=ax, dates=pcs[params.meta_date_col], title=f'by {params.meta_date_col}')\n", - " fname = params.out_figures / 'pca_sample_by_date'\n", + " fname = params.out_figures / f'0_{group}_pca_sample_by_date'\n", " figures[fname.stem] = fname\n", " vaep.savefig(fig, fname)" ] @@ -755,7 +754,7 @@ " size=5,\n", ")\n", "fname = (params.out_figures\n", - " / f'pca_sample_by_{\"_\".join(col_identified_feat.split())}.pdf')\n", + " / f'0_{group}_pca_sample_by_{\"_\".join(col_identified_feat.split())}.pdf')\n", "figures[fname.stem] = fname\n", "vaep.savefig(fig, fname)" ] @@ -778,7 +777,7 @@ " height=600 # 2 inches x 300 dpi\n", ")\n", "fname = (params.out_figures\n", - " / f'pca_sample_by_{\"_\".join(col_identified_feat.split())}_plotly.pdf')\n", + " / f'0_{group}_pca_sample_by_{\"_\".join(col_identified_feat.split())}_plotly.pdf')\n", "figures[fname.stem] = fname\n", "fig.write_image(fname)\n", "fig # stays interactive in html" @@ -828,7 +827,7 @@ " )\n", "_ = vaep.plotting.select_xticks(ax)\n", "fig = ax.get_figure()\n", - "fname = params.out_figures / 'median_boxplot'\n", + "fname = params.out_figures / f'0_{group}_median_boxplot'\n", "figures[fname.stem] = fname\n", "vaep.savefig(fig, fname)\n", "del df_w_date" @@ -881,8 +880,9 @@ " median_sample_intensity[dates.name])\n", " )\n", " fig = ax.get_figure()\n", - " figures['median_scatter'] = params.out_figures / 'median_scatter'\n", - " vaep.savefig(fig, figures['median_scatter'])" + " fname = params.out_figures / f'0_{group}_median_scatter'\n", + " figures[fname.stem] = fname\n", + " vaep.savefig(fig, fname)" ] }, { @@ -1000,6 +1000,7 @@ "metadata": {}, "outputs": [], "source": [ + "group = 2\n", "# if not mnar:\n", "# fake_na, splits.train_X = sample_data(df_long.squeeze(),\n", "# sample_index_to_drop=0,\n", @@ -1076,6 +1077,9 @@ " label=f'MCAR ({N_MCAR:,d})')\n", " ax.legend()\n", " assert len(fake_na) + len(splits.train_X) == len(df_long)\n", + " fname = params.out_figures / f'0_{group}_mnar_mcar_histograms.pdf'\n", + " figures[fname.stem] = fname\n", + " vaep.savefig(fig, fname)\n", "else:\n", " raise ValueError(f\"Invalid MNAR float value (should be betw. 0 and 1): {params.frac_mnar}\")\n", "\n", @@ -1249,6 +1253,7 @@ "metadata": {}, "outputs": [], "source": [ + "group = 3\n", "ax = (splits\n", " .train_X\n", " .plot\n", @@ -1267,7 +1272,7 @@ " legend=True)\n", " )\n", "ax.legend(_legend[:-1])\n", - "fname = params.out_figures / 'test_over_train_split.pdf'\n", + "fname = params.out_figures / f'0_{group}_test_over_train_split.pdf'\n", "figures[fname.name] = fname\n", "vaep.savefig(ax.get_figure(), fname)" ] @@ -1289,7 +1294,7 @@ "ax.legend(_legend)\n", "ax.set_xlabel('Intensity bins')\n", "ax.yaxis.set_major_formatter(\"{x:,.0f}\")\n", - "fname = params.out_figures / 'splits_freq_stacked.pdf'\n", + "fname = params.out_figures / f'0_{group}_splits_freq_stacked.pdf'\n", "figures[fname.name] = fname\n", "vaep.savefig(ax.get_figure(), fname)" ] @@ -1309,7 +1314,7 @@ "ax.legend(_legend[1:])\n", "ax.set_xlabel('Intensity bins')\n", "ax.yaxis.set_major_formatter(\"{x:,.0f}\")\n", - "fname = params.out_figures / 'val_test_split_freq_stacked_.pdf'\n", + "fname = params.out_figures / f'0_{group}_val_test_split_freq_stacked_.pdf'\n", "figures[fname.name] = fname\n", "vaep.savefig(ax.get_figure(), fname)" ] @@ -1338,7 +1343,7 @@ "source": [ "ax = vaep.plotting.data.plot_feat_median_over_prop_missing(\n", " data=splits.train_X, type='scatter')\n", - "fname = params.out_figures / 'intensity_median_vs_prop_missing_scatter_train'\n", + "fname = params.out_figures / f'0_{group}_intensity_median_vs_prop_missing_scatter_train'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), fname)" ] @@ -1351,7 +1356,7 @@ "source": [ "ax = vaep.plotting.data.plot_feat_median_over_prop_missing(\n", " data=splits.train_X, type='boxplot')\n", - "fname = params.out_figures / 'intensity_median_vs_prop_missing_boxplot_train'\n", + "fname = params.out_figures / f'0_{group}_intensity_median_vs_prop_missing_boxplot_train'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), fname)" ] @@ -1359,9 +1364,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "lines_to_next_cell": 0 - }, + "metadata": {}, "outputs": [], "source": [ "medians = (splits\n", @@ -1380,14 +1383,17 @@ " 'validation split': splits.val_y.notna().sum(),\n", " 'training split': splits.train_X.notna().sum()}\n", " ).plot.box(by='medians',\n", - " subplots=True,\n", " boxprops=dict(linewidth=s),\n", " flierprops=dict(markersize=s),\n", " ax=ax)\n", "for ax in s_axes:\n", " _ = ax.set_xticklabels(ax.get_xticklabels(),\n", " rotation=45,\n", - " horizontalalignment='right')" + " horizontalalignment='right')\n", + "\n", + "fname = params.out_figures / f'0_{group}_intensity_median_vs_prop_missing_boxplot_val_train'\n", + "figures[fname.stem] = fname\n", + "vaep.savefig(ax.get_figure(), fname)" ] }, { diff --git a/project/01_0_split_data.py b/project/01_0_split_data.py index 87b745709..6b5e19770 100644 --- a/project/01_0_split_data.py +++ b/project/01_0_split_data.py @@ -91,8 +91,6 @@ def add_meta_data(df: pd.DataFrame, df_meta: pd.DataFrame): frac_non_train: float = 0.1 # fraction of non training data (validation and test split) frac_mnar: float = 0.0 # fraction of missing not at random data, rest: missing completely at random -meta_date_col: str = 'Content Creation Date' -meta_cat_col: str = 'Software Version' # %% args = vaep.nb.get_params(args, globals=globals()) @@ -128,7 +126,7 @@ def add_meta_data(df: pd.DataFrame, df_meta: pd.DataFrame): f"File format (extension): {FILE_EXT} (!specifies data loading function!)") # %% -# ! factor out file reading to a separate module, not class +# # ! factor out file reading to a separate module, not class # AnalyzePeptides.from_csv constructor = getattr(AnalyzePeptides, FILE_FORMAT_TO_CONSTRUCTOR[FILE_EXT]) analysis = constructor(fname=params.FN_INTENSITIES, @@ -371,10 +369,11 @@ def join_as_str(seq): # ### Histogram of features per sample # %% +group = 1 ax = df.notna().sum(axis=1).hist() ax.set_xlabel('features per eligable sample') ax.set_ylabel('observations') -fname = params.out_figures / 'hist_features_per_sample' +fname = params.out_figures / f'0_{group}_hist_features_per_sample' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), fname) @@ -385,7 +384,7 @@ def join_as_str(seq): horizontalalignment='right') ax.set_xlabel('feature prevalence') ax.set_ylabel('observations') -fname = params.out_figures / 'feature_prevalence' +fname = params.out_figures / f'0_{group}_feature_prevalence' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), fname) @@ -398,21 +397,21 @@ def join_as_str(seq): ax, bins = vaep.plotting.data.plot_histogram_intensities( df.stack(), min_max=min_max) -fname = params.out_figures / 'intensity_distribution_overall' +fname = params.out_figures / f'0_{group}_intensity_distribution_overall' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), fname) # %% ax = vaep.plotting.data.plot_feat_median_over_prop_missing( data=df, type='scatter') -fname = params.out_figures / 'intensity_median_vs_prop_missing_scatter' +fname = params.out_figures / f'0_{group}_intensity_median_vs_prop_missing_scatter' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), fname) # %% ax = vaep.plotting.data.plot_feat_median_over_prop_missing( data=df, type='boxplot') -fname = params.out_figures / 'intensity_median_vs_prop_missing_boxplot' +fname = params.out_figures / f'0_{group}_intensity_median_vs_prop_missing_boxplot' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), fname) @@ -443,7 +442,7 @@ def join_as_str(seq): analyzers.seaborn_scatter( pcs[pcs_name], ax, meta=pcs[params.meta_cat_col], title=f"by {params.meta_cat_col}") fname = (params.out_figures - / f'pca_sample_by_{"_".join(params.meta_cat_col.split())}') + / f'0_{group}_pca_sample_by_{"_".join(params.meta_cat_col.split())}') figures[fname.stem] = fname vaep.savefig(fig, fname) @@ -452,7 +451,7 @@ def join_as_str(seq): fig, ax = plt.subplots() analyzers.plot_date_map( df=pcs[pcs_name], ax=ax, dates=pcs[params.meta_date_col], title=f'by {params.meta_date_col}') - fname = params.out_figures / 'pca_sample_by_date' + fname = params.out_figures / f'0_{group}_pca_sample_by_date' figures[fname.stem] = fname vaep.savefig(fig, fname) @@ -470,7 +469,7 @@ def join_as_str(seq): size=5, ) fname = (params.out_figures - / f'pca_sample_by_{"_".join(col_identified_feat.split())}.pdf') + / f'0_{group}_pca_sample_by_{"_".join(col_identified_feat.split())}.pdf') figures[fname.stem] = fname vaep.savefig(fig, fname) @@ -487,7 +486,7 @@ def join_as_str(seq): height=600 # 2 inches x 300 dpi ) fname = (params.out_figures - / f'pca_sample_by_{"_".join(col_identified_feat.split())}_plotly.pdf') + / f'0_{group}_pca_sample_by_{"_".join(col_identified_feat.split())}_plotly.pdf') figures[fname.stem] = fname fig.write_image(fname) fig # stays interactive in html @@ -515,7 +514,7 @@ def join_as_str(seq): ) _ = vaep.plotting.select_xticks(ax) fig = ax.get_figure() -fname = params.out_figures / 'median_boxplot' +fname = params.out_figures / f'0_{group}_median_boxplot' figures[fname.stem] = fname vaep.savefig(fig, fname) del df_w_date @@ -548,8 +547,9 @@ def join_as_str(seq): median_sample_intensity[dates.name]) ) fig = ax.get_figure() - figures['median_scatter'] = params.out_figures / 'median_scatter' - vaep.savefig(fig, figures['median_scatter']) + fname = params.out_figures / f'0_{group}_median_scatter' + figures[fname.stem] = fname + vaep.savefig(fig, fname) # %% [markdown] # - the closer the labels are there denser the samples are measured around that time. @@ -608,6 +608,7 @@ def join_as_str(seq): df_long.head() # %% +group = 2 # if not mnar: # fake_na, splits.train_X = sample_data(df_long.squeeze(), # sample_index_to_drop=0, @@ -684,6 +685,9 @@ def join_as_str(seq): label=f'MCAR ({N_MCAR:,d})') ax.legend() assert len(fake_na) + len(splits.train_X) == len(df_long) + fname = params.out_figures / f'0_{group}_mnar_mcar_histograms.pdf' + figures[fname.stem] = fname + vaep.savefig(fig, fname) else: raise ValueError(f"Invalid MNAR float value (should be betw. 0 and 1): {params.frac_mnar}") @@ -784,6 +788,7 @@ def join_as_str(seq): print(_legend) # %% +group = 3 ax = (splits .train_X .plot @@ -802,7 +807,7 @@ def join_as_str(seq): legend=True) ) ax.legend(_legend[:-1]) -fname = params.out_figures / 'test_over_train_split.pdf' +fname = params.out_figures / f'0_{group}_test_over_train_split.pdf' figures[fname.name] = fname vaep.savefig(ax.get_figure(), fname) @@ -818,7 +823,7 @@ def join_as_str(seq): ax.legend(_legend) ax.set_xlabel('Intensity bins') ax.yaxis.set_major_formatter("{x:,.0f}") -fname = params.out_figures / 'splits_freq_stacked.pdf' +fname = params.out_figures / f'0_{group}_splits_freq_stacked.pdf' figures[fname.name] = fname vaep.savefig(ax.get_figure(), fname) @@ -832,7 +837,7 @@ def join_as_str(seq): ax.legend(_legend[1:]) ax.set_xlabel('Intensity bins') ax.yaxis.set_major_formatter("{x:,.0f}") -fname = params.out_figures / 'val_test_split_freq_stacked_.pdf' +fname = params.out_figures / f'0_{group}_val_test_split_freq_stacked_.pdf' figures[fname.name] = fname vaep.savefig(ax.get_figure(), fname) @@ -845,14 +850,14 @@ def join_as_str(seq): # %% ax = vaep.plotting.data.plot_feat_median_over_prop_missing( data=splits.train_X, type='scatter') -fname = params.out_figures / 'intensity_median_vs_prop_missing_scatter_train' +fname = params.out_figures / f'0_{group}_intensity_median_vs_prop_missing_scatter_train' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), fname) # %% ax = vaep.plotting.data.plot_feat_median_over_prop_missing( data=splits.train_X, type='boxplot') -fname = params.out_figures / 'intensity_median_vs_prop_missing_boxplot_train' +fname = params.out_figures / f'0_{group}_intensity_median_vs_prop_missing_boxplot_train' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), fname) @@ -873,7 +878,6 @@ def join_as_str(seq): 'validation split': splits.val_y.notna().sum(), 'training split': splits.train_X.notna().sum()} ).plot.box(by='medians', - subplots=True, boxprops=dict(linewidth=s), flierprops=dict(markersize=s), ax=ax) @@ -881,6 +885,11 @@ def join_as_str(seq): _ = ax.set_xticklabels(ax.get_xticklabels(), rotation=45, horizontalalignment='right') + +fname = params.out_figures / f'0_{group}_intensity_median_vs_prop_missing_boxplot_val_train' +figures[fname.stem] = fname +vaep.savefig(ax.get_figure(), fname) + # %% [markdown] # ## Save parameters diff --git a/project/01_2_performance_plots.ipynb b/project/01_2_performance_plots.ipynb index ce690ad6f..18229bd9e 100644 --- a/project/01_2_performance_plots.ipynb +++ b/project/01_2_performance_plots.ipynb @@ -22,9 +22,12 @@ "cell_type": "code", "execution_count": null, "id": "a1e5f978-a0cb-4bb6-98d1-467eda257165", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ + "import logging\n", "import yaml\n", "import random\n", "from pathlib import Path\n", @@ -42,14 +45,15 @@ "from vaep.analyzers import compare_predictions\n", "import vaep.nb\n", "\n", - "pd.options.display.max_rows = 120\n", - "pd.options.display.min_rows = 50\n", + "pd.options.display.max_rows = 30\n", + "pd.options.display.min_rows = 10\n", "pd.options.display.max_colwidth = 100\n", "\n", "plt.rcParams.update({'figure.figsize': (4, 2)})\n", - "vaep.plotting.make_large_descriptors(5)\n", + "vaep.plotting.make_large_descriptors(6)\n", "\n", "logger = vaep.logging.setup_nb_logger()\n", + "logging.getLogger('fontTools').setLevel(logging.WARNING)\n", "\n", "\n", "def load_config_file(fname: Path, first_split='config_') -> dict:\n", @@ -77,7 +81,9 @@ "cell_type": "code", "execution_count": null, "id": "67f5161a", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "# catch passed parameters\n", @@ -129,7 +135,9 @@ "cell_type": "code", "execution_count": null, "id": "ec1509e8-6908-43c3-8909-efbb0229c324", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "args = vaep.nb.get_params(args, globals=globals())\n", @@ -140,7 +148,9 @@ "cell_type": "code", "execution_count": null, "id": "19b33594", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "args = vaep.nb.args_from_dict(args)\n", @@ -151,7 +161,9 @@ "cell_type": "code", "execution_count": null, "id": "59081f60", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "figures = {}\n", @@ -163,7 +175,8 @@ "execution_count": null, "id": "c3e124fb", "metadata": { - "lines_to_next_cell": 2 + "lines_to_next_cell": 2, + "tags": [] }, "outputs": [], "source": [ @@ -178,7 +191,9 @@ "cell_type": "code", "execution_count": null, "id": "747d5e4a", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "# list(sns.color_palette().as_hex()) # string representation of colors\n", @@ -191,7 +206,9 @@ "cell_type": "code", "execution_count": null, "id": "a4ba2a48-dedc-47a9-b2ea-79936dfc48ef", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "data = datasplits.DataSplits.from_folder(\n", @@ -202,7 +219,9 @@ "cell_type": "code", "execution_count": null, "id": "611a8edf", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "fig, axes = plt.subplots(1, 2, sharey=True)\n", @@ -213,8 +232,8 @@ " title='Test split', size=1)\n", "\n", "fig.suptitle(\"Simulated missing values per sample\", size=8)\n", - "\n", - "fname = args.out_figures / 'fake_na_val_test_splits.png'\n", + "group = 1\n", + "fname = args.out_figures / f'2_{group}_fake_na_val_test_splits.png'\n", "figures[fname.stem] = fname\n", "vaep.savefig(fig, name=fname)" ] @@ -231,7 +250,9 @@ "cell_type": "code", "execution_count": null, "id": "2d043b40-5c74-40cc-a5cf-8d22ac5538a8", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "# load frequency of training features...\n", @@ -245,7 +266,9 @@ "cell_type": "code", "execution_count": null, "id": "d8f8c3f4-9896-4f0e-8f93-780f90b22573", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "prop = freq_feat / len(data.train_X.index.levels[0])\n", @@ -256,7 +279,9 @@ "cell_type": "code", "execution_count": null, "id": "9a94ad00-78fd-4541-be5d-68391af99bd5", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "data.to_wide_format()\n", @@ -267,7 +292,9 @@ "cell_type": "code", "execution_count": null, "id": "526626c0-98c7-4741-abae-b6fc8c218f23", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "N_SAMPLES, M_FEAT = data.train_X.shape\n", @@ -278,7 +305,9 @@ "cell_type": "code", "execution_count": null, "id": "f3e738bd-79e9-4714-af4d-f3d0d2893353", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "fname = args.folder_experiment / '01_2_performance_summary.xlsx'\n", @@ -299,7 +328,9 @@ "cell_type": "code", "execution_count": null, "id": "91bc1e12-8477-4eda-a4c2-1f132e468616", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "# model_key could be used as key from config file\n", @@ -328,7 +359,9 @@ "cell_type": "code", "execution_count": null, "id": "af8c112f-fb4f-4dcd-b729-9c9558715d88", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "# index name\n", @@ -339,7 +372,9 @@ "cell_type": "code", "execution_count": null, "id": "8088a91f-6aaa-4b9d-b855-332d2bbf5780", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "# index name\n", @@ -367,7 +402,9 @@ "cell_type": "code", "execution_count": null, "id": "4efc3fe6", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "pred_val = compare_predictions.load_split_prediction_by_modelkey(\n", @@ -378,20 +415,6 @@ "pred_val[MODELS]" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "d5196bcc", - "metadata": {}, - "outputs": [], - "source": [ - "errors_val = (pred_val\n", - " .drop(TARGET_COL, axis=1)\n", - " .sub(pred_val[TARGET_COL], axis=0)\n", - " [MODELS])\n", - "errors_val.describe() # over all samples, and all features" - ] - }, { "cell_type": "markdown", "id": "ad1e732c-235f-4fd9-95cc-a64a2ec09f6c", @@ -403,11 +426,17 @@ { "cell_type": "code", "execution_count": null, - "id": "47df94e9-2436-4cdd-9c6f-47062bac7bee", - "metadata": {}, + "id": "d5196bcc", + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "errors_val.abs().describe() # over all samples, and all features" + "errors_val = (pred_val\n", + " .drop(TARGET_COL, axis=1)\n", + " .sub(pred_val[TARGET_COL], axis=0)\n", + " [MODELS])\n", + "errors_val # over all samples and all features" ] }, { @@ -424,7 +453,9 @@ "cell_type": "code", "execution_count": null, "id": "e94d9dd6-d97d-4e1c-b877-48dc1ae9c7c7", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "ORDER_MODELS = (errors_val\n", @@ -440,7 +471,9 @@ "cell_type": "code", "execution_count": null, "id": "4d6417fc", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "mae_stats_ordered_val = errors_val.abs().describe()[ORDER_MODELS]\n", @@ -463,7 +496,9 @@ "cell_type": "code", "execution_count": null, "id": "36e078fb-2268-41dd-a069-4ca3dc5ca6cf", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "COLORS_TO_USE = vaep.plotting.defaults.assign_colors(list(k.upper() for k in ORDER_MODELS))\n", @@ -474,7 +509,9 @@ "cell_type": "code", "execution_count": null, "id": "a2440887-b5f2-45a1-90cd-d15ef9bfa0a7", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "# For top_N -> define colors\n", @@ -498,7 +535,9 @@ "cell_type": "code", "execution_count": null, "id": "3aa7831e-ebf3-4de4-af6c-c4b2a8b00373", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "pred_val_corr = pred_val.corr()\n", @@ -511,7 +550,7 @@ "ax = vaep.plotting.add_height_to_barplot(ax)\n", "ax.set_xticklabels(ax.get_xticklabels(), rotation=45,\n", " horizontalalignment='right')\n", - "fname = args.out_figures / 'pred_corr_val_overall.pdf'\n", + "fname = args.out_figures / f'2_{group}_pred_corr_val_overall.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), name=fname)\n", "pred_val_corr" @@ -529,7 +568,9 @@ "cell_type": "code", "execution_count": null, "id": "cea24eb1", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "corr_per_sample_val = (pred_val\n", @@ -538,7 +579,8 @@ " lambda df: df.corr().loc[TARGET_COL]\n", " )[ORDER_MODELS])\n", "\n", - "kwargs = dict(ylim=(0.7, 1), rot=90,\n", + "min_corr = int(corr_per_sample_val.min().min() * 10) / 10\n", + "kwargs = dict(ylim=(min_corr, 1), rot=90,\n", " # boxprops=dict(linewidth=1.5),\n", " flierprops=dict(markersize=3),\n", " # title='Corr. betw. fake NA and model pred. per sample on validation data',\n", @@ -546,11 +588,11 @@ "ax = corr_per_sample_val[TOP_N_ORDER].plot.box(**kwargs)\n", "ax.set_xticklabels(ax.get_xticklabels(), rotation=45,\n", " horizontalalignment='right')\n", - "fname = args.out_figures / 'pred_corr_val_per_sample.pdf'\n", + "fname = args.out_figures / f'2_{group}_pred_corr_val_per_sample.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), name=fname)\n", "\n", - "fname = args.out_figures / 'pred_corr_val_per_sample.xlsx'\n", + "fname = args.out_figures / f'2_{group}_pred_corr_val_per_sample.xlsx'\n", "dumps[fname.stem] = fname\n", "with pd.ExcelWriter(fname) as w:\n", " corr_per_sample_val.describe().to_excel(w, sheet_name='summary')\n", @@ -569,7 +611,9 @@ "cell_type": "code", "execution_count": null, "id": "4068d91f-856e-4aa6-9c62-5f1f77a77c4c", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "treshold = vaep.pandas.get_lower_whiskers(\n", @@ -591,26 +635,30 @@ "cell_type": "code", "execution_count": null, "id": "52298acd-73c5-4574-b7fe-8fb6544708cf", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "c_error_min = 4.5\n", "mask = (errors_val[MODELS].abs() > c_error_min).any(axis=1)\n", - "errors_val.loc[mask].sort_index(level=1)" + "errors_val.loc[mask].sort_index(level=1).head()" ] }, { "cell_type": "code", "execution_count": null, "id": "570fc505-ab27-4710-b4c2-adbe72b33898", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "errors_val = errors_val.abs().groupby(\n", " freq_feat.index.name).mean() # absolute error\n", "errors_val = errors_val.join(freq_feat)\n", "errors_val = errors_val.sort_values(by=freq_feat.name, ascending=True)\n", - "errors_val" + "errors_val.head()" ] }, { @@ -625,7 +673,9 @@ "cell_type": "code", "execution_count": null, "id": "ddc98a9f", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "errors_val.describe() # mean of means" @@ -636,7 +686,8 @@ "execution_count": null, "id": "af4f0e81-e9af-4763-908d-f7bdf4a4fed7", "metadata": { - "lines_to_next_cell": 2 + "lines_to_next_cell": 2, + "tags": [] }, "outputs": [], "source": [ @@ -658,7 +709,9 @@ "cell_type": "code", "execution_count": null, "id": "df6923c5-e6f7-4a14-aa8e-d55bf66cf817", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(8, 3))\n", @@ -670,7 +723,7 @@ " palette=TOP_N_COLOR_PALETTE,\n", " metric_name=METRIC,)\n", "ax.set_ylabel(f\"Average error ({METRIC})\")\n", - "fname = args.out_figures / 'errors_binned_by_int_val.pdf'\n", + "fname = args.out_figures / f'2_{group}_errors_binned_by_int_val.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), name=fname)" ] @@ -679,7 +732,9 @@ "cell_type": "code", "execution_count": null, "id": "6122a309-5435-44d2-a6f8-8e9d46b5afae", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "errors_binned.head()\n", @@ -700,7 +755,9 @@ "cell_type": "code", "execution_count": null, "id": "1dc848c6-d39e-4092-9b72-3f6a0e1949e2", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "pred_test = compare_predictions.load_split_prediction_by_modelkey(\n", @@ -725,7 +782,9 @@ "cell_type": "code", "execution_count": null, "id": "8bce941c", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "errors_test_mae = vaep.pandas.calc_errors.get_absolute_error(\n", @@ -739,7 +798,9 @@ "cell_type": "code", "execution_count": null, "id": "ff722dae", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "mae_stats_ordered_test.to_excel(writer, sheet_name='mae_stats_ordered_test', float_format='%.5f')" @@ -749,7 +810,9 @@ "cell_type": "code", "execution_count": null, "id": "629eddae", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "cp_mean_perf = pd.concat([\n", @@ -767,7 +830,9 @@ "cell_type": "code", "execution_count": null, "id": "f639cd92", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "writer.close()" @@ -781,23 +846,25 @@ }, "source": [ "## Intensity distribution as histogram\n", - "plot top 4 models" + "Plot top 4 models predictions for intensities in test data" ] }, { "cell_type": "code", "execution_count": null, "id": "99f7951f", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "min_max = vaep.plotting.data.min_max(pred_test[TARGET_COL])\n", "top_n = 4\n", - "fig, axes = plt.subplots(ncols=4, figsize=(8, 2), sharey=True)\n", + "fig, axes = plt.subplots(ncols=top_n, figsize=(8, 2), sharey=True)\n", "\n", "for model, color, ax in zip(\n", - " ORDER_MODELS[:4],\n", - " COLORS_TO_USE[:4],\n", + " ORDER_MODELS[:top_n],\n", + " COLORS_TO_USE[:top_n],\n", " axes):\n", "\n", " ax, _ = vaep.plotting.data.plot_histogram_intensities(\n", @@ -819,7 +886,7 @@ "\n", "axes[0].set_ylabel('Number of observations')\n", "\n", - "fname = args.out_figures / f'intensity_binned_top_{top_n}_models_test.pdf'\n", + "fname = args.out_figures / f'2_{group}_intensity_binned_top_{top_n}_models_test.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(fig, name=fname)" ] @@ -836,7 +903,9 @@ "cell_type": "code", "execution_count": null, "id": "b42efaec-4556-45e9-a813-66da159e771c", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "pred_test_corr = pred_test.corr()\n", @@ -848,7 +917,7 @@ "ax = vaep.plotting.add_height_to_barplot(ax)\n", "ax.set_xticklabels(ax.get_xticklabels(), rotation=45,\n", " horizontalalignment='right')\n", - "fname = args.out_figures / 'pred_corr_test_overall.pdf'\n", + "fname = args.out_figures / f'2_{group}_pred_corr_test_overall.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), name=fname)\n", "pred_test_corr" @@ -866,7 +935,9 @@ "cell_type": "code", "execution_count": null, "id": "ee088a12-ee60-45d1-bf5a-e07b76413c56", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "corr_per_sample_test = (pred_test\n", @@ -887,9 +958,12 @@ "cell_type": "code", "execution_count": null, "id": "825efac2", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ + "# ! add minimum\n", "kwargs = dict(ylim=(0.7, 1), rot=90,\n", " flierprops=dict(markersize=3),\n", " # title='Corr. betw. fake NA and model predictions per sample on test data',\n", @@ -900,7 +974,7 @@ " .box(**kwargs))\n", "ax.set_xticklabels(ax.get_xticklabels(), rotation=45,\n", " horizontalalignment='right')\n", - "fname = args.out_figures / 'pred_corr_test_per_sample.pdf'\n", + "fname = args.out_figures / f'2_{group}_pred_corr_test_per_sample.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), name=fname)\n", "\n", @@ -922,7 +996,9 @@ "cell_type": "code", "execution_count": null, "id": "77b846e1-00b8-4f61-b5cd-cdc1692787de", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "treshold = vaep.pandas.get_lower_whiskers(\n", @@ -936,7 +1012,9 @@ "cell_type": "code", "execution_count": null, "id": "7bff3764-5063-4399-a182-3ba795fbe99d", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "feature_names = pred_test.index.levels[-1]\n", @@ -949,7 +1027,9 @@ "cell_type": "code", "execution_count": null, "id": "c6145bd0-9b59-490e-9a0e-89475c18663b", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "options = random.sample(set(feature_names), 1)\n", @@ -968,7 +1048,9 @@ "cell_type": "code", "execution_count": null, "id": "6ee92128-4f78-45e9-a607-8e6c4163181a", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "corr_per_feat_test = pred_test.groupby(FEAT_NAME).aggregate(\n", @@ -984,7 +1066,9 @@ "cell_type": "code", "execution_count": null, "id": "8e45b324-eaa0-43e4-b28b-b0f839f91955", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "corr_per_feat_test.loc[too_few_obs].dropna(thresh=3, axis=0)" @@ -994,7 +1078,9 @@ "cell_type": "code", "execution_count": null, "id": "4c9a9ecc-526a-41ac-8a4d-d3a389ea6c07", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "kwargs = dict(rot=90,\n", @@ -1007,7 +1093,7 @@ " )\n", "_ = ax.set_xticklabels(ax.get_xticklabels(), rotation=45,\n", " horizontalalignment='right')\n", - "fname = args.out_figures / 'pred_corr_test_per_feat.pdf'\n", + "fname = args.out_figures / f'2_{group}_pred_corr_test_per_feat.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), name=fname)\n", "dumps[fname.stem] = fname.with_suffix('.xlsx')\n", @@ -1021,7 +1107,9 @@ "cell_type": "code", "execution_count": null, "id": "b38ffdfc-b1b0-4ae0-a47d-5881c534881f", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "feat_count_test = data.test_y.stack().groupby(FEAT_NAME).count()\n", @@ -1034,7 +1122,8 @@ "execution_count": null, "id": "9993d145-8b78-4769-838a-01721900a3c7", "metadata": { - "lines_to_next_cell": 0 + "lines_to_next_cell": 0, + "tags": [] }, "outputs": [], "source": [ @@ -1074,7 +1163,9 @@ "cell_type": "code", "execution_count": null, "id": "829ebc82-587d-47c6-8422-03c610855211", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "metrics = vaep.models.Metrics()\n", @@ -1088,7 +1179,9 @@ "cell_type": "code", "execution_count": null, "id": "f8269d00-9048-4e70-9f39-dab95e103c32", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "n_in_comparison = int(test_metrics.loc['N'].unique()[0])\n", @@ -1099,7 +1192,9 @@ "cell_type": "code", "execution_count": null, "id": "096083d1-bcd2-44a2-94fe-a89b7d204b66", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "_to_plot = test_metrics.loc[METRIC].to_frame().T\n", @@ -1112,7 +1207,8 @@ "execution_count": null, "id": "05a259ef-48bd-4dd0-8dfe-9e2750579383", "metadata": { - "lines_to_next_cell": 2 + "lines_to_next_cell": 2, + "tags": [] }, "outputs": [], "source": [ @@ -1133,7 +1229,9 @@ "cell_type": "code", "execution_count": null, "id": "d3dd53c0-4068-4eac-a5c3-7aaa608e5f8f", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(4, 2))\n", @@ -1146,7 +1244,7 @@ "ax = vaep.plotting.add_height_to_barplot(ax, size=5)\n", "ax = vaep.plotting.add_text_to_barplot(ax, _to_plot.loc[\"text\"], size=5)\n", "ax.set_xticklabels([])\n", - "fname = args.out_figures / 'performance_test.pdf'\n", + "fname = args.out_figures / f'2_{group}_performance_test.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(fig, name=fname)" ] @@ -1156,7 +1254,8 @@ "execution_count": null, "id": "ef92551d", "metadata": { - "lines_to_next_cell": 2 + "lines_to_next_cell": 2, + "tags": [] }, "outputs": [], "source": [ @@ -1181,7 +1280,9 @@ "cell_type": "code", "execution_count": null, "id": "588f7bf3", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(8, 2))\n", @@ -1196,7 +1297,7 @@ " palette=COLORS_TO_USE\n", ")\n", "\n", - "fname = args.out_figures / 'errors_binned_by_feat_medians.pdf'\n", + "fname = args.out_figures / f'2_{group}_test_errors_binned_by_feat_medians.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), name=fname)\n", "\n", @@ -1209,7 +1310,9 @@ "cell_type": "code", "execution_count": null, "id": "b13ecd37", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "(errors_binned\n", @@ -1234,7 +1337,9 @@ "cell_type": "code", "execution_count": null, "id": "3339df97-230f-4cbd-b61d-7aef9a7495e8", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(8, 2))\n", @@ -1246,7 +1351,7 @@ " palette=TOP_N_COLOR_PALETTE,\n", " metric_name=METRIC,\n", ")\n", - "fname = args.out_figures / 'errors_binned_by_int_test.pdf'\n", + "fname = args.out_figures / f'2_{group}_test_errors_binned_by_int.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), name=fname)" ] @@ -1255,7 +1360,9 @@ "cell_type": "code", "execution_count": null, "id": "095f64eb-1c4f-47ae-9a01-d5b05a795779", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "dumps[fname.stem] = fname.with_suffix('.csv')\n", @@ -1277,7 +1384,9 @@ "cell_type": "code", "execution_count": null, "id": "c8f67ae1-40e9-4c2a-af0a-41e627703518", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "figures" @@ -1287,19 +1396,13 @@ "cell_type": "code", "execution_count": null, "id": "b08b442f", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "dumps" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ce4f2c42", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -1307,7 +1410,7 @@ "formats": "ipynb,py:percent" }, "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1321,7 +1424,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.17" }, "toc-autonumbering": true, "vscode": { diff --git a/project/01_2_performance_plots.py b/project/01_2_performance_plots.py index c4146d138..53221562e 100644 --- a/project/01_2_performance_plots.py +++ b/project/01_2_performance_plots.py @@ -8,7 +8,7 @@ # format_version: '1.3' # jupytext_version: 1.15.0 # kernelspec: -# display_name: Python 3 +# display_name: Python 3 (ipykernel) # language: python # name: python3 # --- @@ -27,6 +27,7 @@ # - top N based on validation data # %% +import logging import yaml import random from pathlib import Path @@ -44,14 +45,15 @@ from vaep.analyzers import compare_predictions import vaep.nb -pd.options.display.max_rows = 120 -pd.options.display.min_rows = 50 +pd.options.display.max_rows = 30 +pd.options.display.min_rows = 10 pd.options.display.max_colwidth = 100 plt.rcParams.update({'figure.figsize': (4, 2)}) -vaep.plotting.make_large_descriptors(5) +vaep.plotting.make_large_descriptors(6) logger = vaep.logging.setup_nb_logger() +logging.getLogger('fontTools').setLevel(logging.WARNING) def load_config_file(fname: Path, first_split='config_') -> dict: @@ -138,8 +140,8 @@ def build_text(s): title='Test split', size=1) fig.suptitle("Simulated missing values per sample", size=8) - -fname = args.out_figures / 'fake_na_val_test_splits.png' +group = 1 +fname = args.out_figures / f'2_{group}_fake_na_val_test_splits.png' figures[fname.stem] = fname vaep.savefig(fig, name=fname) @@ -215,18 +217,15 @@ def build_text(s): shared_columns=[TARGET_COL]) pred_val[MODELS] +# %% [markdown] +# Describe absolute error + # %% errors_val = (pred_val .drop(TARGET_COL, axis=1) .sub(pred_val[TARGET_COL], axis=0) [MODELS]) -errors_val.describe() # over all samples, and all features - -# %% [markdown] -# Describe absolute error - -# %% -errors_val.abs().describe() # over all samples, and all features +errors_val # over all samples and all features # %% [markdown] # ## Select top N for plotting and set colors @@ -274,7 +273,7 @@ def build_text(s): ax = vaep.plotting.add_height_to_barplot(ax) ax.set_xticklabels(ax.get_xticklabels(), rotation=45, horizontalalignment='right') -fname = args.out_figures / 'pred_corr_val_overall.pdf' +fname = args.out_figures / f'2_{group}_pred_corr_val_overall.pdf' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) pred_val_corr @@ -289,7 +288,8 @@ def build_text(s): lambda df: df.corr().loc[TARGET_COL] )[ORDER_MODELS]) -kwargs = dict(ylim=(0.7, 1), rot=90, +min_corr = int(corr_per_sample_val.min().min() * 10) / 10 +kwargs = dict(ylim=(min_corr, 1), rot=90, # boxprops=dict(linewidth=1.5), flierprops=dict(markersize=3), # title='Corr. betw. fake NA and model pred. per sample on validation data', @@ -297,11 +297,11 @@ def build_text(s): ax = corr_per_sample_val[TOP_N_ORDER].plot.box(**kwargs) ax.set_xticklabels(ax.get_xticklabels(), rotation=45, horizontalalignment='right') -fname = args.out_figures / 'pred_corr_val_per_sample.pdf' +fname = args.out_figures / f'2_{group}_pred_corr_val_per_sample.pdf' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) -fname = args.out_figures / 'pred_corr_val_per_sample.xlsx' +fname = args.out_figures / f'2_{group}_pred_corr_val_per_sample.xlsx' dumps[fname.stem] = fname with pd.ExcelWriter(fname) as w: corr_per_sample_val.describe().to_excel(w, sheet_name='summary') @@ -323,14 +323,14 @@ def build_text(s): # %% c_error_min = 4.5 mask = (errors_val[MODELS].abs() > c_error_min).any(axis=1) -errors_val.loc[mask].sort_index(level=1) +errors_val.loc[mask].sort_index(level=1).head() # %% errors_val = errors_val.abs().groupby( freq_feat.index.name).mean() # absolute error errors_val = errors_val.join(freq_feat) errors_val = errors_val.sort_values(by=freq_feat.name, ascending=True) -errors_val +errors_val.head() # %% [markdown] # Some interpolated features are missing @@ -358,7 +358,7 @@ def build_text(s): palette=TOP_N_COLOR_PALETTE, metric_name=METRIC,) ax.set_ylabel(f"Average error ({METRIC})") -fname = args.out_figures / 'errors_binned_by_int_val.pdf' +fname = args.out_figures / f'2_{group}_errors_binned_by_int_val.pdf' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) @@ -410,15 +410,15 @@ def build_text(s): # %% [markdown] # ## Intensity distribution as histogram -# plot top 4 models +# Plot top 4 models predictions for intensities in test data # %% min_max = vaep.plotting.data.min_max(pred_test[TARGET_COL]) top_n = 4 -fig, axes = plt.subplots(ncols=4, figsize=(8, 2), sharey=True) +fig, axes = plt.subplots(ncols=top_n, figsize=(8, 2), sharey=True) for model, color, ax in zip( - ORDER_MODELS[:4], - COLORS_TO_USE[:4], + ORDER_MODELS[:top_n], + COLORS_TO_USE[:top_n], axes): ax, _ = vaep.plotting.data.plot_histogram_intensities( @@ -440,7 +440,7 @@ def build_text(s): axes[0].set_ylabel('Number of observations') -fname = args.out_figures / f'intensity_binned_top_{top_n}_models_test.pdf' +fname = args.out_figures / f'2_{group}_intensity_binned_top_{top_n}_models_test.pdf' figures[fname.stem] = fname vaep.savefig(fig, name=fname) @@ -457,7 +457,7 @@ def build_text(s): ax = vaep.plotting.add_height_to_barplot(ax) ax.set_xticklabels(ax.get_xticklabels(), rotation=45, horizontalalignment='right') -fname = args.out_figures / 'pred_corr_test_overall.pdf' +fname = args.out_figures / f'2_{group}_pred_corr_test_overall.pdf' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) pred_test_corr @@ -480,6 +480,7 @@ def build_text(s): corr_per_sample_test.loc[~too_few_obs].describe() # %% +# # ! add minimum kwargs = dict(ylim=(0.7, 1), rot=90, flierprops=dict(markersize=3), # title='Corr. betw. fake NA and model predictions per sample on test data', @@ -490,7 +491,7 @@ def build_text(s): .box(**kwargs)) ax.set_xticklabels(ax.get_xticklabels(), rotation=45, horizontalalignment='right') -fname = args.out_figures / 'pred_corr_test_per_sample.pdf' +fname = args.out_figures / f'2_{group}_pred_corr_test_per_sample.pdf' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) @@ -545,7 +546,7 @@ def build_text(s): ) _ = ax.set_xticklabels(ax.get_xticklabels(), rotation=45, horizontalalignment='right') -fname = args.out_figures / 'pred_corr_test_per_feat.pdf' +fname = args.out_figures / f'2_{group}_pred_corr_test_per_feat.pdf' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) dumps[fname.stem] = fname.with_suffix('.xlsx') @@ -626,7 +627,7 @@ def highlight_min(s, color, tolerence=0.00001): ax = vaep.plotting.add_height_to_barplot(ax, size=5) ax = vaep.plotting.add_text_to_barplot(ax, _to_plot.loc["text"], size=5) ax.set_xticklabels([]) -fname = args.out_figures / 'performance_test.pdf' +fname = args.out_figures / f'2_{group}_performance_test.pdf' figures[fname.stem] = fname vaep.savefig(fig, name=fname) @@ -656,7 +657,7 @@ def highlight_min(s, color, tolerence=0.00001): palette=COLORS_TO_USE ) -fname = args.out_figures / 'errors_binned_by_feat_medians.pdf' +fname = args.out_figures / f'2_{group}_test_errors_binned_by_feat_medians.pdf' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) @@ -687,7 +688,7 @@ def highlight_min(s, color, tolerence=0.00001): palette=TOP_N_COLOR_PALETTE, metric_name=METRIC, ) -fname = args.out_figures / 'errors_binned_by_int_test.pdf' +fname = args.out_figures / f'2_{group}_test_errors_binned_by_int.pdf' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) @@ -703,5 +704,3 @@ def highlight_min(s, color, tolerence=0.00001): # %% dumps - -# %% From a1dfa2b9b7e4bbecf6ab0d28a01a73c4d79a69f2 Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 27 Sep 2023 15:02:22 +0200 Subject: [PATCH 09/70] :alien: update code to pandas 2.0 - update depreciated functionality in pandas -> some scripts might have further depreciation warnings --- vaep/models/collab.py | 2 +- vaep/tests/test_sampling.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/vaep/models/collab.py b/vaep/models/collab.py index bb37a9b46..ff9f461a1 100644 --- a/vaep/models/collab.py +++ b/vaep/models/collab.py @@ -56,7 +56,7 @@ def combine_data(train_df: pd.DataFrame, val_df: pd.DataFrame) -> Tuple[pd.DataF Pandas DataFrame of concatenated samples of training and validation data. Fraction of samples originally in validation data. """ - X = train_df.append(val_df).reset_index() + X = pd.concat([train_df, val_df]).reset_index() frac = len(val_df) / (len(train_df) + len(val_df)) return X, frac diff --git a/vaep/tests/test_sampling.py b/vaep/tests/test_sampling.py index bed514892..813c79331 100644 --- a/vaep/tests/test_sampling.py +++ b/vaep/tests/test_sampling.py @@ -53,5 +53,7 @@ def test_sample_data(random_data): series_sampled) + len(series_not_sampled) assert X.index.difference( series_sampled.index.append(series_not_sampled.index)).empty - assert series_sampled.loc[pd.IndexSlice[:, excluded_feat]].empty - assert not series_not_sampled.loc[pd.IndexSlice[:, excluded_feat]].empty + idx_excluded = series_sampled.index.isin(excluded_feat, level=1) + assert series_sampled.loc[idx_excluded].empty + idx_excluded = series_not_sampled.index.isin(excluded_feat, level=1) + assert not series_not_sampled.loc[idx_excluded].empty From 7118beca6a94db994d115ccce3559acb6c520bbf Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 27 Sep 2023 15:04:04 +0200 Subject: [PATCH 10/70] :heavy_plus_sign: add igraph (for windows) - igraph installation in conda on the fly fails for windows otherwise: https://stackoverflow.com/a/71711600/9684872 --- environment.yml | 10 +++++----- setup.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/environment.yml b/environment.yml index ce3760fba..8bcde8e71 100644 --- a/environment.yml +++ b/environment.yml @@ -47,8 +47,8 @@ dependencies: - jupyter-dash - papermill # execute ipynb's # R packages (listed in NAGuideR) - - r-base #=3.6 - - r-devtools # is it needed for source installs on windows server? + - r-base + - r-devtools # is it needed for source installs on windows server? - r-irkernel - r-reshape2 - r-stringi # + rmarkdown hack for reshape2 @@ -66,6 +66,7 @@ dependencies: - r-rrcov - r-gmm - r-tmvtnorm + - r-igraph # - bioconductor-biocinstaller # - r-imputelcmd # bioconda # - bioconductor-impute @@ -83,6 +84,5 @@ dependencies: # - jupyterlab_code_formatter # - jupyterlab-git - pip: - - -e . - - mrmr-selection - \ No newline at end of file + - -e . + - mrmr-selection diff --git a/setup.py b/setup.py index 8ab824cc7..8bf1ba938 100644 --- a/setup.py +++ b/setup.py @@ -1,2 +1,2 @@ from setuptools import setup -setup() \ No newline at end of file +setup() From 1da36a617af75afd87536c54e0deee4d1570c49e Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 27 Sep 2023 15:09:00 +0200 Subject: [PATCH 11/70] :bug: remove peptides from reversed protein groups - reversed decoy sequence matches should be removed (it's only a few) --- vaep/io/data_objects.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/vaep/io/data_objects.py b/vaep/io/data_objects.py index 62d81ac71..51c4b61e0 100644 --- a/vaep/io/data_objects.py +++ b/vaep/io/data_objects.py @@ -401,7 +401,7 @@ def __call__(self, folders, # # check df for redundant information (same feature value for all entries) -usecols = mq.COLS_ + ['Potential contaminant', mq.mq_col.SEQUENCE, 'PEP'] +usecols = mq.COLS_ + ['Potential contaminant', 'Reverse', mq.mq_col.SEQUENCE, 'PEP'] def count_peptides(folders: List[Path], dump=True, @@ -414,14 +414,17 @@ def count_peptides(folders: List[Path], dump=True, peptides = pd.read_table(folder / 'peptides.txt', usecols=usecols, index_col=0) - mask = (peptides[mq.mq_col.INTENSITY] == 0) | ( - peptides["Potential contaminant"] == '+') + mask = ((peptides[mq.mq_col.INTENSITY] == 0) + | (peptides["Potential contaminant"] == '+') + | (peptides["Reverse"] == '+') + ) peptides = peptides.loc[~mask] c.update(peptides.index) if dump: - fpath_dict[folder.stem] = dump_to_csv(peptides.drop('Potential contaminant', axis=1), - folder=folder, outfolder=outfolder, - parent_folder_fct=parent_folder_fct) + fpath_dict[folder.stem] = dump_to_csv(peptides.drop( + ['Potential contaminant', 'Reverse'], axis=1), + folder=folder, outfolder=outfolder, + parent_folder_fct=parent_folder_fct) ret = {'counter': c, 'dumps': fpath_dict} return ret From 972540697a5e766789ccf6328c3f20ee6a0f381b Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Wed, 27 Sep 2023 17:08:00 +0200 Subject: [PATCH 12/70] :bug: set index correctly --- project/erda_02_mq_count_features.ipynb | 18 ++++-------------- project/erda_02_mq_count_features.py | 12 +++++------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/project/erda_02_mq_count_features.ipynb b/project/erda_02_mq_count_features.ipynb index 2dd052693..40e4ab5da 100644 --- a/project/erda_02_mq_count_features.ipynb +++ b/project/erda_02_mq_count_features.ipynb @@ -23,6 +23,7 @@ "import yaml\n", "\n", "import pandas as pd\n", + "from tqdm.notebook import tqdm\n", "\n", "import vaep.pandas\n", "from vaep.io.data_objects import PeptideCounter\n", @@ -77,7 +78,7 @@ "outputs": [], "source": [ "fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id\n", - "df_ids = pd.read_csv(fn_id_old_new)\n", + "df_ids = pd.read_csv(fn_id_old_new, index_col=0)\n", "df_ids" ] }, @@ -97,7 +98,7 @@ }, "outputs": [], "source": [ - "folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids['Sample ID']}\n", + "folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids.index}\n", "# folders_dict = {p.stem : p.parent / p.stem for p in folders_dict}\n", "# folders_dict\n", "folders = [Path(folder_path) for folder_path in folders_dict.values()]" @@ -261,7 +262,7 @@ }, "outputs": [], "source": [ - "for k, v in peptide_counter.dumps.items():\n", + "for k, v in tqdm(peptide_counter.dumps.items()):\n", " old_name = v\n", " new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv')\n", " try:\n", @@ -270,17 +271,6 @@ " logging.warning(f\"File not found: {old_name}\")" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "new_name" - ] - }, { "cell_type": "code", "execution_count": null, diff --git a/project/erda_02_mq_count_features.py b/project/erda_02_mq_count_features.py index a92c3a098..02f17f9cb 100644 --- a/project/erda_02_mq_count_features.py +++ b/project/erda_02_mq_count_features.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.15.0 +# jupytext_version: 1.15.1 # kernelspec: # display_name: Python 3 (ipykernel) # language: python @@ -24,6 +24,7 @@ import yaml import pandas as pd +from tqdm.notebook import tqdm import vaep.pandas from vaep.io.data_objects import PeptideCounter @@ -58,14 +59,14 @@ # %% fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id -df_ids = pd.read_csv(fn_id_old_new) +df_ids = pd.read_csv(fn_id_old_new, index_col=0) df_ids # %% [markdown] # Select files and create list of folders # %% -folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids['Sample ID']} +folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids.index} # folders_dict = {p.stem : p.parent / p.stem for p in folders_dict} # folders_dict folders = [Path(folder_path) for folder_path in folders_dict.values()] @@ -130,7 +131,7 @@ c = peptide_counter.sum_over_files(folders=folders) # %% -for k, v in peptide_counter.dumps.items(): +for k, v in tqdm(peptide_counter.dumps.items()): old_name = v new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv') try: @@ -138,9 +139,6 @@ except FileNotFoundError: logging.warning(f"File not found: {old_name}") -# %% -new_name - # %% c.most_common(10) # peptide_counter.counter.most_common(10) From 4085578d95f9797849cae6fd452799d552db0177 Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 27 Sep 2023 17:35:02 +0200 Subject: [PATCH 13/70] :bug: target renamed plot in rule - grouping of plots was not reflected in Snakemake workflow --- project/workflow/Snakefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/workflow/Snakefile b/project/workflow/Snakefile index 867d4c8ce..fe9e67482 100644 --- a/project/workflow/Snakefile +++ b/project/workflow/Snakefile @@ -11,7 +11,7 @@ logger.info(f"{folder_experiment = }") rule all: input: - f"{folder_experiment}/figures/errors_binned_by_int_test.pdf", + f"{folder_experiment}/figures/2_1_test_errors_binned_by_int.pdf", f"{folder_experiment}/01_2_performance_summary.xlsx" @@ -31,7 +31,7 @@ rule comparison: ), output: xlsx="{folder_experiment}/01_2_performance_summary.xlsx", - pdf="{folder_experiment}/figures/errors_binned_by_int_test.pdf", + pdf="{folder_experiment}/figures/2_1_test_errors_binned_by_int.pdf", nb="{folder_experiment}" f"/{nb}", params: meta_data=config["fn_rawfile_metadata"], From 2dbd185a72fbe84ce5de6addb1ad3f699fb95679 Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 27 Sep 2023 10:21:57 +0200 Subject: [PATCH 14/70] :construction: prepare cluster execution - aim: specify long run time for R jobs with a high max - run long running job in parallel on one big node --- project/config/cluster_script.sh | 31 +++++++++++++++++++++++++++++++ project/workflow/Snakefile | 11 +++++++++++ 2 files changed, 42 insertions(+) create mode 100644 project/config/cluster_script.sh diff --git a/project/config/cluster_script.sh b/project/config/cluster_script.sh new file mode 100644 index 000000000..82a204f96 --- /dev/null +++ b/project/config/cluster_script.sh @@ -0,0 +1,31 @@ +#!/bin/sh +### Note: No commands may be executed until after the #PBS lines +### Account information +#PBS -W group_list=cpr_10006 -A cpr_10006 +### Job name (comment out the next line to get the name of the script used as the job name) +#PBS -N snakemake +### Output files (comment out the next 2 lines to get the job name used instead) +#PBS -e ${PBS_JOBNAME}.${PBS_JOBID}.e +#PBS -o ${PBS_JOBNAME}.${PBS_JOBID}.o +### Email notification: a=aborts, b=begins, e=ends, n=no notifications +#PBS -m ae -M henry.webel@cpr.ku.dk +### Number of nodes +#PBS -l nodes=1:ppn=1,mem=8gb +### Requesting timeformat is ::: +#PBS -l walltime=1:12:00:00 +### Forward all environment variables + + + +# Go to the directory from where the job was submitted (initial directory is $HOME) +echo Working directory is $PBS_O_WORKDIR +cd $PBS_O_WORKDIR + + +snakemake --jobs 10 -k -p --latency-wait 60 --rerun-incomplete \ +--cluster "qsub -l walltime={resources.walltime},nodes=1:ppn={threads},mem={resources.mem_mb}mb"\ +" -W group_list=cpr_10006 -A cpr_10006 "\ +# "-e {params.logdir} -o {params.logdir}" \ +--cluster-status "python qsub-status.py" && +echo "done" || +echo "failed" \ No newline at end of file diff --git a/project/workflow/Snakefile b/project/workflow/Snakefile index fe9e67482..af7b85c31 100644 --- a/project/workflow/Snakefile +++ b/project/workflow/Snakefile @@ -5,9 +5,16 @@ from snakemake.logging import logger configfile: "config/single_dev_dataset/proteinGroups_N50/config.yaml" + +MAX_WALLTIME = '24:00:00' +# Thinnode resources sharing: 40 cores and 196 GB RAM (minus 2GB for snakemake) +# JOB_RAM_MB = int(204_800 / 40 * config['THREATS_MQ']) +JOB_RAM_MB = '4gb' folder_experiment = config["folder_experiment"] logger.info(f"{folder_experiment = }") +# local rules are excuted in the process (job) running snakemake +localrules: all rule all: input: @@ -80,6 +87,10 @@ rule train_NAGuideR_model: output: nb="{folder_experiment}/01_1_train_NAGuideR_{method}.ipynb", dump=temp("{folder_experiment}/preds/pred_all_{method}.csv") + resources: + mem_mb = JOB_RAM_MB, walltime = MAX_WALLTIME + threads: + 1 # R is single threaded benchmark: "{folder_experiment}/01_1_train_NAGuideR_{method}.tsv" params: From c5236f78a3bc543651472bf7496ea8259c6c049b Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Wed, 27 Sep 2023 23:09:35 +0200 Subject: [PATCH 15/70] :sparkles: enable torque cluster execution - log file paths for submitted jobs added (should be unique) - -V: forward set environment for submitted job --- ...ster_script.sh => run_snakemake_cluster.sh} | 11 +++++++---- project/workflow/Snakefile | 18 ++++++++++++++++-- 2 files changed, 23 insertions(+), 6 deletions(-) rename project/{config/cluster_script.sh => run_snakemake_cluster.sh} (81%) diff --git a/project/config/cluster_script.sh b/project/run_snakemake_cluster.sh similarity index 81% rename from project/config/cluster_script.sh rename to project/run_snakemake_cluster.sh index 82a204f96..f1bce9aaf 100644 --- a/project/config/cluster_script.sh +++ b/project/run_snakemake_cluster.sh @@ -21,11 +21,14 @@ echo Working directory is $PBS_O_WORKDIR cd $PBS_O_WORKDIR +. ~/setup_conda.sh +conda activate vaep snakemake --jobs 10 -k -p --latency-wait 60 --rerun-incomplete \ +--default-resources walltime=3600 \ --cluster "qsub -l walltime={resources.walltime},nodes=1:ppn={threads},mem={resources.mem_mb}mb"\ -" -W group_list=cpr_10006 -A cpr_10006 "\ -# "-e {params.logdir} -o {params.logdir}" \ ---cluster-status "python qsub-status.py" && +" -W group_list=cpr_10006 -A cpr_10006 -V"\ +" -e {params.err} -o {params.out}" \ +--cluster-status "python ../workflows/maxquant/qsub-status.py" && echo "done" || -echo "failed" \ No newline at end of file +echo "failed" diff --git a/project/workflow/Snakefile b/project/workflow/Snakefile index af7b85c31..26dcc77d5 100644 --- a/project/workflow/Snakefile +++ b/project/workflow/Snakefile @@ -28,6 +28,7 @@ MODELS = config["models"].copy() if config["NAGuideR_methods"]: MODELS += config["NAGuideR_methods"] +nb_stem = "01_2_performance_summary" rule comparison: input: nb=nb, @@ -37,12 +38,14 @@ rule comparison: model=MODELS, ), output: - xlsx="{folder_experiment}/01_2_performance_summary.xlsx", + xlsx=f"{{folder_experiment}}/{nb_stem}.xlsx", pdf="{folder_experiment}/figures/2_1_test_errors_binned_by_int.pdf", nb="{folder_experiment}" f"/{nb}", params: meta_data=config["fn_rawfile_metadata"], models=",".join(MODELS), + err = f"{{folder_experiment}}/logs/{nb_stem}.e", + out = f"{{folder_experiment}}/logs/{nb_stem}.o" shell: "papermill {input.nb} {output.nb}" " -r fn_rawfile_metadata {params.meta_data:q}" @@ -71,6 +74,8 @@ rule transform_NAGuideR_predictions: benchmark: "{folder_experiment}/"f"{nb_stem}.tsv", params: + err = f"{{folder_experiment}}/logs/{nb_stem}.e", + out = f"{{folder_experiment}}/logs/{nb_stem}.o", folder_experiment="{folder_experiment}", # https://snakemake.readthedocs.io/en/stable/snakefiles/rules.html#non-file-parameters-for-rules dumps_as_str=lambda wildcards, input: ','.join(input.dumps) @@ -94,6 +99,8 @@ rule train_NAGuideR_model: benchmark: "{folder_experiment}/01_1_train_NAGuideR_{method}.tsv" params: + err = "{folder_experiment}/logs/{method}.e", + out = "{folder_experiment}/logs/{method}.o", folder_experiment="{folder_experiment}", method="{method}", shell: @@ -103,15 +110,18 @@ rule train_NAGuideR_model: " -r folder_experiment {params.folder_experiment}" " && jupyter nbconvert --to html {output.nb}" +nb_stem = "01_0_transform_data_to_wide_format" rule transform_data_to_wide_format: input: - nb="01_0_transform_data_to_wide_format.ipynb", + nb=f"{nb_stem}.ipynb", train_split="{folder_experiment}/data/train_X.csv", output: nb="{folder_experiment}/01_0_transform_data_to_wide_format.ipynb", train_split=temp("{folder_experiment}/data/data_wide_sample_cols.csv"), params: folder_experiment="{folder_experiment}", + err = f"{{folder_experiment}}/logs/{nb_stem}.e", + out = f"{{folder_experiment}}/logs/{nb_stem}.o", shell: "papermill {input.nb} {output.nb}" " -r folder_experiment {params.folder_experiment}" @@ -132,6 +142,8 @@ rule train_models: params: folder_experiment="{folder_experiment}", meta_data=config["fn_rawfile_metadata"], + err = "{folder_experiment}/logs/{model}.e", + out = "{folder_experiment}/logs/{model}.o" shell: "papermill {input.nb} {output.nb}" " -f {input.configfile}" @@ -156,6 +168,8 @@ rule create_splits: params: folder_experiment="{folder_experiment}", meta_data=config["fn_rawfile_metadata"], + err = "{folder_experiment}/logs/create_splits.e", + out = "{folder_experiment}/logs/create_splits.o" shell: "papermill {input.nb} {output.nb}" " -f {input.configfile}" From 6d8ecbf9336cb18e46caedf62e68055b677d3eb7 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 29 Sep 2023 15:55:36 +0200 Subject: [PATCH 16/70] :bug: remove reversed sequences from evidence - precursors from reversed protein sequences are removed from the evidence table - adapt code to use local information (yaml files) --- project/erda_02_mq_count_features.ipynb | 26 ++++++++++++++++++++----- project/erda_02_mq_count_features.py | 25 ++++++++++++++++++++---- vaep/io/data_objects.py | 9 ++++++--- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/project/erda_02_mq_count_features.ipynb b/project/erda_02_mq_count_features.ipynb index 40e4ab5da..7174dbe98 100644 --- a/project/erda_02_mq_count_features.ipynb +++ b/project/erda_02_mq_count_features.ipynb @@ -44,7 +44,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Use samples previously loaded." + "Use samples previously loaded. Specified MQ output folders are in `eligable_files.yaml`\n", + "\n", + "```yaml\n", + "# example of eligable_files.yaml\n", + "files:\n", + " - example_folder\n", + "```\n", + "\n", + "and the name to folder path are in `file_paths.yaml`\n", + "\n", + "```yaml\n", + "# example of file_paths.yaml\n", + "example_folder: path/to/example_folder\n", + "```\n", + "\n" ] }, { @@ -55,8 +69,8 @@ }, "outputs": [], "source": [ - "ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml')\n", - "MAP_FOLDER_PATH = Path('config/file_paths')\n", + "ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml') # acutally MQ txt folders, not files...\n", + "MAP_FOLDER_PATH = Path('config/file_paths.yaml')\n", "\n", "with open(ELIGABLE_FILES_YAML) as f:\n", " files = set(yaml.safe_load(f)['files'])\n", @@ -98,10 +112,11 @@ }, "outputs": [], "source": [ - "folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids.index}\n", + "folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in files}\n", "# folders_dict = {p.stem : p.parent / p.stem for p in folders_dict}\n", "# folders_dict\n", - "folders = [Path(folder_path) for folder_path in folders_dict.values()]" + "folders = [Path(folder_path) for folder_path in folders_dict.values()]\n", + "len(folders)" ] }, { @@ -393,6 +408,7 @@ " evidence_cols.Protein_group_IDs,\n", " evidence_cols.Intensity,\n", " evidence_cols.Score,\n", + " evidence_cols.Reverse,\n", " evidence_cols.Potential_contaminant]\n", "\n", "evidence_selected = vaep.io.data_objects.select_evidence(evidence[use_cols])\n", diff --git a/project/erda_02_mq_count_features.py b/project/erda_02_mq_count_features.py index 02f17f9cb..9e140d55e 100644 --- a/project/erda_02_mq_count_features.py +++ b/project/erda_02_mq_count_features.py @@ -41,11 +41,26 @@ logging.info(f"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}") # %% [markdown] -# Use samples previously loaded. +# Use samples previously loaded. Specified MQ output folders are in `eligable_files.yaml` +# +# ```yaml +# # example of eligable_files.yaml +# files: +# - example_folder +# ``` +# +# and the name to folder path are in `file_paths.yaml` +# +# ```yaml +# # example of file_paths.yaml +# example_folder: path/to/example_folder +# ``` +# +# # %% -ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml') -MAP_FOLDER_PATH = Path('config/file_paths') +ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml') # acutally MQ txt folders, not files... +MAP_FOLDER_PATH = Path('config/file_paths.yaml') with open(ELIGABLE_FILES_YAML) as f: files = set(yaml.safe_load(f)['files']) @@ -66,10 +81,11 @@ # Select files and create list of folders # %% -folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in df_ids.index} +folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in files} # folders_dict = {p.stem : p.parent / p.stem for p in folders_dict} # folders_dict folders = [Path(folder_path) for folder_path in folders_dict.values()] +len(folders) # %% @@ -198,6 +214,7 @@ evidence_cols.Protein_group_IDs, evidence_cols.Intensity, evidence_cols.Score, + evidence_cols.Reverse, evidence_cols.Potential_contaminant] evidence_selected = vaep.io.data_objects.select_evidence(evidence[use_cols]) diff --git a/vaep/io/data_objects.py b/vaep/io/data_objects.py index 51c4b61e0..666b471af 100644 --- a/vaep/io/data_objects.py +++ b/vaep/io/data_objects.py @@ -467,8 +467,11 @@ def load_dump(fpath): def select_evidence(df_evidence: pd.DataFrame) -> pd.DataFrame: - mask = (df_evidence[evidence_cols.Potential_contaminant] - == '+') | (df_evidence[evidence_cols.Intensity] == 0) + mask = ((df_evidence[['Reverse', 'Potential contaminant']] + .notna() + .any(axis=1)) + | (df_evidence[evidence_cols.Intensity] == 0) + ) evidence = df_evidence.loc[~mask].drop( evidence_cols.Potential_contaminant, axis=1) evidence = evidence.dropna(subset=[evidence_cols.Intensity]) @@ -580,7 +583,7 @@ def load_and_process_proteinGroups(folder: Union[str, Path], pg = pd.read_table(folder / 'proteinGroups.txt', usecols=use_cols) mask = pg[[pg_cols.Only_identified_by_site, pg_cols.Reverse, - pg_cols.Potential_contaminant]].notna().sum(axis=1) > 0 + pg_cols.Potential_contaminant]].notna().any(axis=1) pg = pg.loc[~mask] mask = pg[pg_cols.Intensity] > 1 pg = pg.loc[mask] From 8a4ab8b28ec256767265994befd176ff25a2eaa9 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 29 Sep 2023 17:18:31 +0200 Subject: [PATCH 17/70] :arrow_up: remove constraints on pandas and pytorch - colab uses pandas and pytorch two - datetime_is_numeric parameter removed from describe, see https://pandas.pydata.org/docs/whatsnew/v2.0.0.html --- project/00_0_0_lftp_upload_commands.ipynb | 2 +- project/00_0_0_lftp_upload_commands.py | 2 +- project/00_0_hela_metadata_rawfiles.ipynb | 2 +- project/00_0_hela_metadata_rawfiles.py | 2 +- project/00_3_1_pride_metadata_analysis.ipynb | 2 +- project/00_3_1_pride_metadata_analysis.py | 2 +- project/01_0_split_data.ipynb | 7 +++---- project/01_0_split_data.py | 7 +++---- setup.cfg | 4 ++-- vaep/pandas/__init__.py | 2 +- 10 files changed, 15 insertions(+), 17 deletions(-) diff --git a/project/00_0_0_lftp_upload_commands.ipynb b/project/00_0_0_lftp_upload_commands.ipynb index 1d9ae4337..3ea94597a 100644 --- a/project/00_0_0_lftp_upload_commands.ipynb +++ b/project/00_0_0_lftp_upload_commands.ipynb @@ -113,7 +113,7 @@ "metadata": {}, "outputs": [], "source": [ - "meta_stats = df_meta.describe(include='all', datetime_is_numeric=True)\n", + "meta_stats = df_meta.describe(include='all')\n", "meta_stats.T" ] }, diff --git a/project/00_0_0_lftp_upload_commands.py b/project/00_0_0_lftp_upload_commands.py index 17cc26be2..03b71f264 100644 --- a/project/00_0_0_lftp_upload_commands.py +++ b/project/00_0_0_lftp_upload_commands.py @@ -71,7 +71,7 @@ def rename(fname, new_sample_id, new_folder=None, ext=None): # %% -meta_stats = df_meta.describe(include='all', datetime_is_numeric=True) +meta_stats = df_meta.describe(include='all') meta_stats.T # %% [markdown] diff --git a/project/00_0_hela_metadata_rawfiles.ipynb b/project/00_0_hela_metadata_rawfiles.ipynb index 3971259e4..b4ca77ca5 100644 --- a/project/00_0_hela_metadata_rawfiles.ipynb +++ b/project/00_0_hela_metadata_rawfiles.ipynb @@ -101,7 +101,7 @@ "metadata": {}, "outputs": [], "source": [ - "meta_stats = df_meta_rawfiles.describe(include='all', datetime_is_numeric=True)\n", + "meta_stats = df_meta_rawfiles.describe(include='all')\n", "meta_stats.T" ] }, diff --git a/project/00_0_hela_metadata_rawfiles.py b/project/00_0_hela_metadata_rawfiles.py index 03a501db0..2241611e8 100644 --- a/project/00_0_hela_metadata_rawfiles.py +++ b/project/00_0_hela_metadata_rawfiles.py @@ -58,7 +58,7 @@ print(msg) # %% -meta_stats = df_meta_rawfiles.describe(include='all', datetime_is_numeric=True) +meta_stats = df_meta_rawfiles.describe(include='all') meta_stats.T # %% [markdown] diff --git a/project/00_3_1_pride_metadata_analysis.ipynb b/project/00_3_1_pride_metadata_analysis.ipynb index d68e970a9..54452b7d9 100644 --- a/project/00_3_1_pride_metadata_analysis.ipynb +++ b/project/00_3_1_pride_metadata_analysis.ipynb @@ -177,7 +177,7 @@ "metadata": {}, "outputs": [], "source": [ - "meta_stats = df_meta.describe(include='all', datetime_is_numeric=True)\n", + "meta_stats = df_meta.describe(include='all')\n", "meta_stats.T.to_excel(excel_writer, sheet_name='des_stats', **writer_args)\n", "\n", "view = meta_stats.loc[:, (meta_stats.loc['unique'] > 1)\n", diff --git a/project/00_3_1_pride_metadata_analysis.py b/project/00_3_1_pride_metadata_analysis.py index c6ad55d12..105a82d7a 100644 --- a/project/00_3_1_pride_metadata_analysis.py +++ b/project/00_3_1_pride_metadata_analysis.py @@ -103,7 +103,7 @@ # ## Varying data between runs # %% -meta_stats = df_meta.describe(include='all', datetime_is_numeric=True) +meta_stats = df_meta.describe(include='all') meta_stats.T.to_excel(excel_writer, sheet_name='des_stats', **writer_args) view = meta_stats.loc[:, (meta_stats.loc['unique'] > 1) diff --git a/project/01_0_split_data.ipynb b/project/01_0_split_data.ipynb index 32cdb3713..ed62a0e31 100644 --- a/project/01_0_split_data.ipynb +++ b/project/01_0_split_data.ipynb @@ -327,8 +327,7 @@ "metadata": {}, "outputs": [], "source": [ - "df_meta.describe(datetime_is_numeric=True,\n", - " percentiles=np.linspace(0.05, 0.95, 10))" + "df_meta.describe(percentiles=np.linspace(0.05, 0.95, 10))" ] }, { @@ -373,7 +372,7 @@ "metadata": {}, "outputs": [], "source": [ - "meta_stats = df_meta.describe(include='all', datetime_is_numeric=True)\n", + "meta_stats = df_meta.describe(include='all')\n", "meta_stats" ] }, @@ -697,7 +696,7 @@ "metadata": {}, "outputs": [], "source": [ - "pcs.describe(include='all', datetime_is_numeric=True).T" + "pcs.describe(include='all').T" ] }, { diff --git a/project/01_0_split_data.py b/project/01_0_split_data.py index 6b5e19770..fc41e698f 100644 --- a/project/01_0_split_data.py +++ b/project/01_0_split_data.py @@ -227,8 +227,7 @@ def join_as_str(seq): # %% -df_meta.describe(datetime_is_numeric=True, - percentiles=np.linspace(0.05, 0.95, 10)) +df_meta.describe(percentiles=np.linspace(0.05, 0.95, 10)) # %% [markdown] # select samples with a minimum retention time @@ -251,7 +250,7 @@ def join_as_str(seq): df_meta = df_meta.sort_values(params.meta_date_col) # %% -meta_stats = df_meta.describe(include='all', datetime_is_numeric=True) +meta_stats = df_meta.describe(include='all') meta_stats # %% [markdown] @@ -434,7 +433,7 @@ def join_as_str(seq): pcs # %% -pcs.describe(include='all', datetime_is_numeric=True).T +pcs.describe(include='all').T # %% if params.meta_cat_col: diff --git a/setup.cfg b/setup.cfg index 4e33952ce..9ac3edd9e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,9 +22,9 @@ include_package_data = True install_requires = numpy matplotlib - pandas<2 + pandas plotly - torch<2 + torch scikit-learn>=1.0 scipy seaborn diff --git a/vaep/pandas/__init__.py b/vaep/pandas/__init__.py index b10ce763a..489765682 100644 --- a/vaep/pandas/__init__.py +++ b/vaep/pandas/__init__.py @@ -73,7 +73,7 @@ def unique_cols(s: pd.Series) -> bool: def show_columns_with_variation(df: pd.DataFrame) -> pd.DataFrame: - df_describe = df.describe(include='all', datetime_is_numeric=True) + df_describe = df.describe(include='all') col_mask = (df_describe.loc['unique'] > 1) | ( df_describe.loc['std'] > 0.01) return df.loc[:, col_mask] From 12218c5b339d543876179ff9735769f3a72ce0c9 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 9 Oct 2023 11:30:34 +0200 Subject: [PATCH 18/70] :bug: make pandas 2.0 compatible - append is depreciated. --- vaep/io/data_objects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vaep/io/data_objects.py b/vaep/io/data_objects.py index 666b471af..23c4f1c71 100644 --- a/vaep/io/data_objects.py +++ b/vaep/io/data_objects.py @@ -597,7 +597,7 @@ def load_and_process_proteinGroups(folder: Union[str, Path], pg = vaep.pandas.select_max_by(df=pg.loc[~mask_no_gene], grouping_columns=[pg_cols.Gene_names], selection_column=pg_cols.Score) - pg = pg.append(pg_no_gene) + pg = pd.concat([pg, pg_no_gene]) pg = pg.set_index(pg_cols.Protein_IDs) return pg From 26dc891900a88d784579d5583f65b855deff2e3d Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Mon, 9 Oct 2023 15:42:28 +0200 Subject: [PATCH 19/70] :sparkles::memo: specify task specific log files in case a tool, e.g. the torque scheduler, creates log files, these can be requested per task (job): in the run_snakememake_cluster bash script, this is done using -e and -o options. --- project/run_snakemake_cluster.sh | 3 +- project/workflow/Snakefile | 89 ++++++++++++++++++++------------ 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/project/run_snakemake_cluster.sh b/project/run_snakemake_cluster.sh index f1bce9aaf..d7a8c4396 100644 --- a/project/run_snakemake_cluster.sh +++ b/project/run_snakemake_cluster.sh @@ -28,7 +28,8 @@ snakemake --jobs 10 -k -p --latency-wait 60 --rerun-incomplete \ --default-resources walltime=3600 \ --cluster "qsub -l walltime={resources.walltime},nodes=1:ppn={threads},mem={resources.mem_mb}mb"\ " -W group_list=cpr_10006 -A cpr_10006 -V"\ -" -e {params.err} -o {params.out}" \ +" -e {params.err} -o {params.out}"\ +" -N ${prefix}.{params.name}" \ --cluster-status "python ../workflows/maxquant/qsub-status.py" && echo "done" || echo "failed" diff --git a/project/workflow/Snakefile b/project/workflow/Snakefile index 26dcc77d5..c3489e842 100644 --- a/project/workflow/Snakefile +++ b/project/workflow/Snakefile @@ -3,23 +3,31 @@ Document how all the notebooks for a single experiment are connected. """ from snakemake.logging import logger + configfile: "config/single_dev_dataset/proteinGroups_N50/config.yaml" -MAX_WALLTIME = '24:00:00' +MAX_WALLTIME = "24:00:00" # Thinnode resources sharing: 40 cores and 196 GB RAM (minus 2GB for snakemake) # JOB_RAM_MB = int(204_800 / 40 * config['THREATS_MQ']) -JOB_RAM_MB = '4gb' +JOB_RAM_MB = "4gb" folder_experiment = config["folder_experiment"] logger.info(f"{folder_experiment = }") + # local rules are excuted in the process (job) running snakemake -localrules: all +localrules: + all, + comparison, + transform_NAGuideR_predictions, + transform_data_to_wide_format, + create_splits, + rule all: input: f"{folder_experiment}/figures/2_1_test_errors_binned_by_int.pdf", - f"{folder_experiment}/01_2_performance_summary.xlsx" + f"{folder_experiment}/01_2_performance_summary.xlsx", nb = "01_2_performance_plots.ipynb" @@ -29,6 +37,8 @@ if config["NAGuideR_methods"]: MODELS += config["NAGuideR_methods"] nb_stem = "01_2_performance_summary" + + rule comparison: input: nb=nb, @@ -44,8 +54,8 @@ rule comparison: params: meta_data=config["fn_rawfile_metadata"], models=",".join(MODELS), - err = f"{{folder_experiment}}/logs/{nb_stem}.e", - out = f"{{folder_experiment}}/logs/{nb_stem}.o" + err=f"{{folder_experiment}}/{nb_stem}.e", + out=f"{{folder_experiment}}/{nb_stem}.o", shell: "papermill {input.nb} {output.nb}" " -r fn_rawfile_metadata {params.meta_data:q}" @@ -53,56 +63,63 @@ rule comparison: " -r models {params.models:q}" " && jupyter nbconvert --to html {output.nb}" + ########################################################################################## # train NaGuideR methods nb_stem = "01_1_transfer_NAGuideR_pred" + + rule transform_NAGuideR_predictions: - input: + input: dumps=expand( "{{folder_experiment}}/preds/pred_all_{method}.csv", method=config["NAGuideR_methods"], ), nb=f"{nb_stem}.ipynb", output: - # "{{folder_experiment}}/preds/pred_real_na_{method}.csv"), - expand( ( - "{{folder_experiment}}/preds/pred_val_{method}.csv", - "{{folder_experiment}}/preds/pred_test_{method}.csv"), + # "{{folder_experiment}}/preds/pred_real_na_{method}.csv"), + expand( + ( + "{{folder_experiment}}/preds/pred_val_{method}.csv", + "{{folder_experiment}}/preds/pred_test_{method}.csv", + ), method=config["NAGuideR_methods"], ), nb="{folder_experiment}/01_1_transfer_NAGuideR_pred.ipynb", benchmark: - "{folder_experiment}/"f"{nb_stem}.tsv", + "{folder_experiment}/" f"{nb_stem}.tsv" params: - err = f"{{folder_experiment}}/logs/{nb_stem}.e", - out = f"{{folder_experiment}}/logs/{nb_stem}.o", + err=f"{{folder_experiment}}/{nb_stem}.e", + out=f"{{folder_experiment}}/{nb_stem}.o", folder_experiment="{folder_experiment}", # https://snakemake.readthedocs.io/en/stable/snakefiles/rules.html#non-file-parameters-for-rules - dumps_as_str=lambda wildcards, input: ','.join(input.dumps) + dumps_as_str=lambda wildcards, input: ",".join(input.dumps), shell: "papermill {input.nb} {output.nb}" " -r folder_experiment {params.folder_experiment}" " -p dumps {params.dumps_as_str}" " && jupyter nbconvert --to html {output.nb}" + rule train_NAGuideR_model: input: nb="01_1_train_NAGuideR_methods.ipynb", train_split="{folder_experiment}/data/data_wide_sample_cols.csv", output: nb="{folder_experiment}/01_1_train_NAGuideR_{method}.ipynb", - dump=temp("{folder_experiment}/preds/pred_all_{method}.csv") + dump="{folder_experiment}/preds/pred_all_{method}.csv", resources: - mem_mb = JOB_RAM_MB, walltime = MAX_WALLTIME - threads: - 1 # R is single threaded + mem_mb=JOB_RAM_MB, + walltime=MAX_WALLTIME, + threads: 1 # R is single threaded benchmark: "{folder_experiment}/01_1_train_NAGuideR_{method}.tsv" params: - err = "{folder_experiment}/logs/{method}.e", - out = "{folder_experiment}/logs/{method}.o", + err="{folder_experiment}/01_1_train_NAGuideR_{method}.e", + out="{folder_experiment}/01_1_train_NAGuideR_{method}.o", folder_experiment="{folder_experiment}", method="{method}", + name="{method}", shell: "papermill {input.nb} {output.nb}" " -r train_split {input.train_split}" @@ -110,23 +127,27 @@ rule train_NAGuideR_model: " -r folder_experiment {params.folder_experiment}" " && jupyter nbconvert --to html {output.nb}" + nb_stem = "01_0_transform_data_to_wide_format" + + rule transform_data_to_wide_format: input: nb=f"{nb_stem}.ipynb", train_split="{folder_experiment}/data/train_X.csv", output: nb="{folder_experiment}/01_0_transform_data_to_wide_format.ipynb", - train_split=temp("{folder_experiment}/data/data_wide_sample_cols.csv"), + train_split="{folder_experiment}/data/data_wide_sample_cols.csv", params: folder_experiment="{folder_experiment}", - err = f"{{folder_experiment}}/logs/{nb_stem}.e", - out = f"{{folder_experiment}}/logs/{nb_stem}.o", + err=f"{{folder_experiment}}/{nb_stem}.e", + out=f"{{folder_experiment}}/{nb_stem}.o", shell: "papermill {input.nb} {output.nb}" " -r folder_experiment {params.folder_experiment}" " && jupyter nbconvert --to html {output.nb}" + ########################################################################################## # train models in python rule train_models: @@ -136,14 +157,15 @@ rule train_models: configfile=config["config_train"], output: nb="{folder_experiment}/01_1_train_{model}.ipynb", - pred="{folder_experiment}/preds/pred_test_{model}.csv" + pred="{folder_experiment}/preds/pred_test_{model}.csv", benchmark: "{folder_experiment}/01_1_train_{model}.tsv" params: folder_experiment="{folder_experiment}", meta_data=config["fn_rawfile_metadata"], - err = "{folder_experiment}/logs/{model}.e", - out = "{folder_experiment}/logs/{model}.o" + err="{folder_experiment}/01_1_train_{model}.e", + out="{folder_experiment}/01_1_train_{model}.o", + name="{model}", shell: "papermill {input.nb} {output.nb}" " -f {input.configfile}" @@ -156,23 +178,24 @@ rule train_models: ########################################################################################## # Create Data splits # separate workflow by level -> provide custom configs -nb = "01_0_split_data.ipynb" +nb_stem = "01_0_split_data" + rule create_splits: input: - nb=nb, + nb=f"{nb_stem}.ipynb", configfile=config["config_split"], output: train_split="{folder_experiment}/data/train_X.csv", - nb="{folder_experiment}" f"/{nb}", + nb="{folder_experiment}" f"/{nb_stem}.ipynb", params: folder_experiment="{folder_experiment}", meta_data=config["fn_rawfile_metadata"], - err = "{folder_experiment}/logs/create_splits.e", - out = "{folder_experiment}/logs/create_splits.o" + err=f"{{folder_experiment}}/{nb_stem}.e", + out=f"{{folder_experiment}}/{nb_stem}.o", shell: "papermill {input.nb} {output.nb}" " -f {input.configfile}" " -r folder_experiment {params.folder_experiment}" " -p fn_rawfile_metadata {params.meta_data}" - " && jupyter nbconvert --to html {output.nb}" \ No newline at end of file + " && jupyter nbconvert --to html {output.nb}" From c7503e133984e019dcf29f6a6bca2efc64ed4ec5 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Mon, 9 Oct 2023 15:46:32 +0200 Subject: [PATCH 20/70] :wrench: set default to cpu (no accelerator, e.g. gpu) --- project/config/appl_ald_data/plasma/aggPeptides/train.yaml | 2 +- .../config/appl_ald_data/plasma/grid_search/config_grid.yaml | 2 +- project/config/config_grid.yaml | 2 +- project/config/config_grid_small.yaml | 2 +- project/config/grid_search_small_data/config_grid.yaml | 2 +- project/config/knn_comparison/ald_pgs_all/config.yaml | 2 +- project/config/knn_comparison/hela_pgs_large/config.yaml | 2 +- project/config/permuted_dataset/config.yaml | 2 +- project/config/single_dev_dataset/evidence/config.yaml | 1 + project/config/single_dev_dataset/evidence/train_CF.yaml | 2 +- project/config/single_dev_dataset/evidence/train_DAE.yaml | 2 +- project/config/single_dev_dataset/evidence/train_VAE.yaml | 2 +- project/config/single_dev_dataset/evidence_N50/train_CF.yaml | 2 +- project/config/single_dev_dataset/evidence_N50/train_DAE.yaml | 2 +- project/config/single_dev_dataset/evidence_N50/train_VAE.yaml | 2 +- project/config/single_dev_dataset/peptides/config.yaml | 1 + project/config/single_dev_dataset/peptides/train_CF.yaml | 2 +- project/config/single_dev_dataset/peptides/train_DAE.yaml | 2 +- project/config/single_dev_dataset/peptides/train_VAE.yaml | 2 +- project/config/single_dev_dataset/peptides_N50/train_CF.yaml | 2 +- project/config/single_dev_dataset/peptides_N50/train_DAE.yaml | 2 +- project/config/single_dev_dataset/peptides_N50/train_VAE.yaml | 2 +- project/config/single_dev_dataset/proteinGroups/config.yaml | 2 +- project/config/single_dev_dataset/proteinGroups/train_CF.yaml | 2 +- project/config/single_dev_dataset/proteinGroups/train_DAE.yaml | 2 +- project/config/single_dev_dataset/proteinGroups/train_VAE.yaml | 2 +- 26 files changed, 26 insertions(+), 24 deletions(-) diff --git a/project/config/appl_ald_data/plasma/aggPeptides/train.yaml b/project/config/appl_ald_data/plasma/aggPeptides/train.yaml index 82c32663f..6bffe907c 100644 --- a/project/config/appl_ald_data/plasma/aggPeptides/train.yaml +++ b/project/config/appl_ald_data/plasma/aggPeptides/train.yaml @@ -3,5 +3,5 @@ file_format: pkl latent_dim: 20 hidden_layers: "512" sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/appl_ald_data/plasma/grid_search/config_grid.yaml b/project/config/appl_ald_data/plasma/grid_search/config_grid.yaml index dcddbc2eb..27737b9f4 100644 --- a/project/config/appl_ald_data/plasma/grid_search/config_grid.yaml +++ b/project/config/appl_ald_data/plasma/grid_search/config_grid.yaml @@ -29,4 +29,4 @@ levels: config_split: 'config/appl_ald_data/plasma/{level}/split.yaml' config_train: 'placeholder.yaml' name_template: run_LD_{latent_dim}_E_{epochs_max} -cuda: True \ No newline at end of file +cuda: False \ No newline at end of file diff --git a/project/config/config_grid.yaml b/project/config/config_grid.yaml index 6d9e4a737..f1e9531e6 100644 --- a/project/config/config_grid.yaml +++ b/project/config/config_grid.yaml @@ -33,7 +33,7 @@ config_split: 'config/single_dev_dataset/{level}/split.yaml' file_format: csv config_train: 'placeholder.yaml' name_template: run/LD_{latent_dim}_E_{epochs_max} -cuda: True +cuda: False NAGuideR_methods: models: - CF diff --git a/project/config/config_grid_small.yaml b/project/config/config_grid_small.yaml index 69d18852b..4c0bb90ee 100644 --- a/project/config/config_grid_small.yaml +++ b/project/config/config_grid_small.yaml @@ -19,7 +19,7 @@ levels: config_split: 'config/single_dev_dataset/{level}/split.yaml' file_format: csv config_train: 'placeholder.yaml' -cuda: True +cuda: False NAGuideR_methods: models: - Median diff --git a/project/config/grid_search_small_data/config_grid.yaml b/project/config/grid_search_small_data/config_grid.yaml index 67dbeb14f..0ba053433 100644 --- a/project/config/grid_search_small_data/config_grid.yaml +++ b/project/config/grid_search_small_data/config_grid.yaml @@ -32,7 +32,7 @@ levels: config_split: 'config/grid_search_small_data/{level}_split.yaml' config_train: 'placeholder.yaml' name_template: run_LD_{latent_dim}_E_{epochs_max} -cuda: True +cuda: False NAGuideR_methods: models: - CF diff --git a/project/config/knn_comparison/ald_pgs_all/config.yaml b/project/config/knn_comparison/ald_pgs_all/config.yaml index d212ba056..d7b966561 100644 --- a/project/config/knn_comparison/ald_pgs_all/config.yaml +++ b/project/config/knn_comparison/ald_pgs_all/config.yaml @@ -3,7 +3,7 @@ config_train: runs/knn_comparison/ald_pgs_all/configs_train/train_{model}.yaml folder_experiment: runs/knn_comparison/ald_pgs_all fn_rawfile_metadata: data/ALD_study/processed/raw_meta.csv file_format: pkl -cuda: True +cuda: False models: - Median: model: Median diff --git a/project/config/knn_comparison/hela_pgs_large/config.yaml b/project/config/knn_comparison/hela_pgs_large/config.yaml index 0b15d1da1..160b92411 100644 --- a/project/config/knn_comparison/hela_pgs_large/config.yaml +++ b/project/config/knn_comparison/hela_pgs_large/config.yaml @@ -3,7 +3,7 @@ config_train: runs/knn_comparison/hela_pgs_large/configs_train/train_{model}.yam folder_experiment: runs/knn_comparison/hela_pgs_large fn_rawfile_metadata: data/dev_datasets/df_intensities_proteinGroups_long/metadata.csv file_format: csv -cuda: True +cuda: False models: - Median: model: Median diff --git a/project/config/permuted_dataset/config.yaml b/project/config/permuted_dataset/config.yaml index b917f88c4..7c36c7999 100644 --- a/project/config/permuted_dataset/config.yaml +++ b/project/config/permuted_dataset/config.yaml @@ -3,7 +3,7 @@ config_split: config/permuted_dataset/split.yaml # proteinGroups config_train: config/single_dev_dataset/proteinGroups/train_{model}.yaml folder_experiment: runs/permuted #/proteinGroups fn_rawfile_metadata: # no metadata for permuted data -cuda: True +cuda: False models: - Median - CF diff --git a/project/config/single_dev_dataset/evidence/config.yaml b/project/config/single_dev_dataset/evidence/config.yaml index 031a42614..e1b633f67 100644 --- a/project/config/single_dev_dataset/evidence/config.yaml +++ b/project/config/single_dev_dataset/evidence/config.yaml @@ -2,6 +2,7 @@ config_split: config/single_dev_dataset/evidence/split.yaml config_train: config/single_dev_dataset/evidence/train_{model}.yaml folder_experiment: runs/dev_dataset_large/evidence fn_rawfile_metadata: data/dev_datasets/df_intensities_evidence_long/metadata.csv +cuda: False models: - Median - CF diff --git a/project/config/single_dev_dataset/evidence/train_CF.yaml b/project/config/single_dev_dataset/evidence/train_CF.yaml index 9324564b6..2068cc158 100644 --- a/project/config/single_dev_dataset/evidence/train_CF.yaml +++ b/project/config/single_dev_dataset/evidence/train_CF.yaml @@ -3,5 +3,5 @@ latent_dim: 50 batch_size: 32768 epochs_max: 100 sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/evidence/train_DAE.yaml b/project/config/single_dev_dataset/evidence/train_DAE.yaml index 05d68c70b..41ffcb066 100644 --- a/project/config/single_dev_dataset/evidence/train_DAE.yaml +++ b/project/config/single_dev_dataset/evidence/train_DAE.yaml @@ -4,5 +4,5 @@ batch_size: 64 epochs_max: 100 hidden_layers: "512" sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/evidence/train_VAE.yaml b/project/config/single_dev_dataset/evidence/train_VAE.yaml index 87565f179..b3a22c8bb 100644 --- a/project/config/single_dev_dataset/evidence/train_VAE.yaml +++ b/project/config/single_dev_dataset/evidence/train_VAE.yaml @@ -4,5 +4,5 @@ batch_size: 64 epochs_max: 100 hidden_layers: "512" sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/evidence_N50/train_CF.yaml b/project/config/single_dev_dataset/evidence_N50/train_CF.yaml index 2ca3c5ac1..802add8cd 100644 --- a/project/config/single_dev_dataset/evidence_N50/train_CF.yaml +++ b/project/config/single_dev_dataset/evidence_N50/train_CF.yaml @@ -4,5 +4,5 @@ latent_dim: 50 batch_size: 4096 epochs_max: 30 sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/evidence_N50/train_DAE.yaml b/project/config/single_dev_dataset/evidence_N50/train_DAE.yaml index cbbd89129..feefc16e1 100644 --- a/project/config/single_dev_dataset/evidence_N50/train_DAE.yaml +++ b/project/config/single_dev_dataset/evidence_N50/train_DAE.yaml @@ -4,5 +4,5 @@ batch_size: 10 epochs_max: 100 hidden_layers: "256" sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True diff --git a/project/config/single_dev_dataset/evidence_N50/train_VAE.yaml b/project/config/single_dev_dataset/evidence_N50/train_VAE.yaml index 4eba2e370..ea2604123 100644 --- a/project/config/single_dev_dataset/evidence_N50/train_VAE.yaml +++ b/project/config/single_dev_dataset/evidence_N50/train_VAE.yaml @@ -6,5 +6,5 @@ batch_size: 10 epochs_max: 100 hidden_layers: "256" sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/peptides/config.yaml b/project/config/single_dev_dataset/peptides/config.yaml index 6a81ae3b5..66bce7a37 100644 --- a/project/config/single_dev_dataset/peptides/config.yaml +++ b/project/config/single_dev_dataset/peptides/config.yaml @@ -2,6 +2,7 @@ config_split: config/single_dev_dataset/peptides/split.yaml config_train: config/single_dev_dataset/peptides/train_{model}.yaml folder_experiment: runs/dev_dataset_large/peptides fn_rawfile_metadata: data/dev_datasets/df_intensities_peptides_long/metadata.csv +cuda: False models: - Median # ~ 1:20 min - CF # ~ 12:07 min diff --git a/project/config/single_dev_dataset/peptides/train_CF.yaml b/project/config/single_dev_dataset/peptides/train_CF.yaml index 9324564b6..2068cc158 100644 --- a/project/config/single_dev_dataset/peptides/train_CF.yaml +++ b/project/config/single_dev_dataset/peptides/train_CF.yaml @@ -3,5 +3,5 @@ latent_dim: 50 batch_size: 32768 epochs_max: 100 sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/peptides/train_DAE.yaml b/project/config/single_dev_dataset/peptides/train_DAE.yaml index 8f94a9b07..aa1e0bd06 100644 --- a/project/config/single_dev_dataset/peptides/train_DAE.yaml +++ b/project/config/single_dev_dataset/peptides/train_DAE.yaml @@ -4,5 +4,5 @@ batch_size: 64 epochs_max: 100 hidden_layers: "1024" sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/peptides/train_VAE.yaml b/project/config/single_dev_dataset/peptides/train_VAE.yaml index 462cf3e3a..dd3a9cca6 100644 --- a/project/config/single_dev_dataset/peptides/train_VAE.yaml +++ b/project/config/single_dev_dataset/peptides/train_VAE.yaml @@ -4,5 +4,5 @@ batch_size: 64 epochs_max: 50 hidden_layers: "512" sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/peptides_N50/train_CF.yaml b/project/config/single_dev_dataset/peptides_N50/train_CF.yaml index 2ca3c5ac1..802add8cd 100644 --- a/project/config/single_dev_dataset/peptides_N50/train_CF.yaml +++ b/project/config/single_dev_dataset/peptides_N50/train_CF.yaml @@ -4,5 +4,5 @@ latent_dim: 50 batch_size: 4096 epochs_max: 30 sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/peptides_N50/train_DAE.yaml b/project/config/single_dev_dataset/peptides_N50/train_DAE.yaml index c337dcf74..d01114dad 100644 --- a/project/config/single_dev_dataset/peptides_N50/train_DAE.yaml +++ b/project/config/single_dev_dataset/peptides_N50/train_DAE.yaml @@ -4,5 +4,5 @@ batch_size: 10 epochs_max: 100 hidden_layers: "512" sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/peptides_N50/train_VAE.yaml b/project/config/single_dev_dataset/peptides_N50/train_VAE.yaml index 09d9c3ff7..6239b5bd2 100644 --- a/project/config/single_dev_dataset/peptides_N50/train_VAE.yaml +++ b/project/config/single_dev_dataset/peptides_N50/train_VAE.yaml @@ -6,5 +6,5 @@ batch_size: 10 epochs_max: 100 hidden_layers: "512_256" sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/proteinGroups/config.yaml b/project/config/single_dev_dataset/proteinGroups/config.yaml index 3f470f6e6..d098ec2e4 100644 --- a/project/config/single_dev_dataset/proteinGroups/config.yaml +++ b/project/config/single_dev_dataset/proteinGroups/config.yaml @@ -2,7 +2,7 @@ config_split: config/single_dev_dataset/proteinGroups/split.yaml config_train: config/single_dev_dataset/proteinGroups/train_{model}.yaml folder_experiment: runs/dev_dataset_large/proteinGroups fn_rawfile_metadata: data/dev_datasets/df_intensities_proteinGroups_long/metadata.csv -cuda: True +cuda: False models: - Median - CF diff --git a/project/config/single_dev_dataset/proteinGroups/train_CF.yaml b/project/config/single_dev_dataset/proteinGroups/train_CF.yaml index f879b0f13..58370bd9c 100644 --- a/project/config/single_dev_dataset/proteinGroups/train_CF.yaml +++ b/project/config/single_dev_dataset/proteinGroups/train_CF.yaml @@ -4,5 +4,5 @@ latent_dim: 50 batch_size: 32768 epochs_max: 100 sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/proteinGroups/train_DAE.yaml b/project/config/single_dev_dataset/proteinGroups/train_DAE.yaml index 86ac35fb9..cab0c8246 100644 --- a/project/config/single_dev_dataset/proteinGroups/train_DAE.yaml +++ b/project/config/single_dev_dataset/proteinGroups/train_DAE.yaml @@ -5,5 +5,5 @@ batch_size: 64 epochs_max: 100 hidden_layers: "512" sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/proteinGroups/train_VAE.yaml b/project/config/single_dev_dataset/proteinGroups/train_VAE.yaml index 7d3f29462..2dc70a4ae 100644 --- a/project/config/single_dev_dataset/proteinGroups/train_VAE.yaml +++ b/project/config/single_dev_dataset/proteinGroups/train_VAE.yaml @@ -6,5 +6,5 @@ batch_size: 64 epochs_max: 50 hidden_layers: "512" sample_idx_position: 0 -cuda: True +cuda: False save_pred_real_na: True \ No newline at end of file From 6e780a205ca39ab2a9cb00d0a82d117c59aff8d3 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Mon, 9 Oct 2023 17:13:17 +0200 Subject: [PATCH 21/70] :sparkles: torque (qsub) script with parameters using -v - submit required parameters using the -v option, e.g. qsub run_snakemake_cluster.sh \ -N snakemake_exp0 \ -v configfile=path_to/config.yaml,prefix=exp0 --- project/run_snakemake_cluster.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/project/run_snakemake_cluster.sh b/project/run_snakemake_cluster.sh index d7a8c4396..b5b6dd13c 100644 --- a/project/run_snakemake_cluster.sh +++ b/project/run_snakemake_cluster.sh @@ -21,10 +21,33 @@ echo Working directory is $PBS_O_WORKDIR cd $PBS_O_WORKDIR +cd pimms/project # throws an error, but is not consequential. + +# Get the values of the parameters from the environment variables +prefix=${prefix:-""} +configfile=${configfile:-""} + +# Check if the values are empty +if [ -z "$prefix" ]; then + echo "Error: Missing required parameters: prefix" + exit 1 +# Check if the values are empty +elif [ -z "$configfile" ]; then + echo "Error: Missing required parameters: configfile" + exit 1 +else + echo " # found parameters, see above:" + echo prefix: $prefix + echo configfile: $configfile + echo '####################################################################' +fi + + . ~/setup_conda.sh conda activate vaep snakemake --jobs 10 -k -p --latency-wait 60 --rerun-incomplete \ +--configfile $configfile \ --default-resources walltime=3600 \ --cluster "qsub -l walltime={resources.walltime},nodes=1:ppn={threads},mem={resources.mem_mb}mb"\ " -W group_list=cpr_10006 -A cpr_10006 -V"\ From 0fcc08635cc473776a3bdeb051fe95a031f2a2f6 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Mon, 9 Oct 2023 17:21:22 +0200 Subject: [PATCH 22/70] :art::bug: reverse column for evidence, rename all dumps - rename also protein groups and precursors (evidence) dumps - drop entries from reversed sequences in evidence files --- project/erda_02_mq_count_features.ipynb | 188 ++++++++++++++++++++---- project/erda_02_mq_count_features.py | 44 +++++- vaep/io/data_objects.py | 4 +- 3 files changed, 197 insertions(+), 39 deletions(-) diff --git a/project/erda_02_mq_count_features.ipynb b/project/erda_02_mq_count_features.ipynb index 7174dbe98..364f6d618 100644 --- a/project/erda_02_mq_count_features.ipynb +++ b/project/erda_02_mq_count_features.ipynb @@ -69,7 +69,7 @@ }, "outputs": [], "source": [ - "ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml') # acutally MQ txt folders, not files...\n", + "ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml') # acutally MQ txt folders, not files...\n", "MAP_FOLDER_PATH = Path('config/file_paths.yaml')\n", "\n", "with open(ELIGABLE_FILES_YAML) as f:\n", @@ -112,6 +112,7 @@ }, "outputs": [], "source": [ + "files = [file for file in files if file in df_ids.index]\n", "folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in files}\n", "# folders_dict = {p.stem : p.parent / p.stem for p in folders_dict}\n", "# folders_dict\n", @@ -138,7 +139,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Random example" + "## Random example - peptides" ] }, { @@ -325,7 +326,7 @@ "Collapsed": "false" }, "source": [ - "## Peptides by charge\n", + "## Random example - precursors\n", "\n", "- count peptides by charge state (which are aggregated in `peptides.txt`)" ] @@ -333,7 +334,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "evidence_cols = vaep.pandas.get_columns_accessor(mq_output.evidence.reset_index())\n", @@ -343,7 +346,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "evidence = mq_output.evidence.set_index(evidence_cols.Charge, append=True)\n", @@ -360,7 +365,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "evidence.Modifications.value_counts()" @@ -369,7 +376,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "vaep.pandas.prop_unique_index(evidence)" @@ -389,7 +398,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "mask = evidence[evidence_cols.Intensity].isna()\n", @@ -399,7 +410,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "evidence_cols = vaep.io.data_objects.evidence_cols\n", @@ -418,7 +431,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "evidence_selected = evidence_selected.sort_values(by=['Sequence', 'Charge', 'Score'], ascending=False)\n", @@ -428,7 +443,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "evidence_selected = vaep.pandas.select_max_by(\n", @@ -440,7 +457,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "c = Counter()\n", @@ -451,7 +470,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "example = evidence.loc[c.most_common(10)[0][0]]\n", @@ -469,7 +490,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "evidence[evidence_cols.Type].value_counts()" @@ -488,7 +511,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "evidence[evidence_cols.Protein_group_IDs].value_counts()" @@ -498,7 +523,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Count peptides based on evidence files" + "## Count precursors based on evidence files" ] }, { @@ -513,6 +538,23 @@ "c = evidence_counter.sum_over_files(folders=folders)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "for k, v in tqdm(evidence_counter.dumps.items()):\n", + " old_name = v\n", + " new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv')\n", + " try:\n", + " os.rename(old_name, new_name)\n", + " except FileNotFoundError:\n", + " logging.warning(f\"File not found: {old_name}\")" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -527,7 +569,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "mq_output.proteinGroups.describe(include='all')" @@ -536,7 +580,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "pg_cols = vaep.pandas.get_columns_accessor(mq_output.proteinGroups.reset_index())\n", @@ -546,7 +592,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "use_cols = [\n", @@ -572,7 +620,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "msg = \"Omitting the data drops {0:.3f} % of the data.\"\n", @@ -584,7 +634,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "selection = mq_output.proteinGroups.loc[~mask, use_cols]\n", @@ -597,7 +649,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "mask = selection.Intensity > 0\n", @@ -609,7 +663,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "selection = selection.loc[mask]" @@ -629,7 +685,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "gene_set = selection[pg_cols.Gene_names].str.split(';')\n", @@ -644,7 +702,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "cols = vaep.pandas.get_columns_accessor(selection)\n", @@ -665,7 +725,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "gene_sets_counts = selection[cols.Gene_names].value_counts()\n", @@ -684,7 +746,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "non_unique_genes = gene_sets_counts.loc[gene_sets_counts > 1].index\n", @@ -703,7 +767,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "selection.loc[selection[cols.Number_of_Genes] > 2]" @@ -712,7 +778,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "logging.info(f\"Selection shape before dropping duplicates by gene: {selection.shape}\")\n", @@ -725,7 +793,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "selection = vaep.pandas.select_max_by(df=selection.loc[~mask_no_gene].reset_index(), grouping_columns=[\n", @@ -739,10 +809,38 @@ { "cell_type": "code", "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "selection = pd.concat([selection, selection_no_gene])\n", + "selection" + ] + }, + { + "cell_type": "markdown", "metadata": {}, + "source": [ + "The above is done in the function for loading and processing protein groups" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "selection = selection.append(selection_no_gene)" + "vaep.io.data_objects.load_and_process_proteinGroups(random_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Count protein groups (genes) based on proteinGroups files" ] }, { @@ -760,7 +858,33 @@ { "cell_type": "code", "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "for k, v in tqdm(protein_groups_counter.dumps.items()):\n", + " old_name = v\n", + " new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv')\n", + " try:\n", + " os.rename(old_name, new_name)\n", + " except FileNotFoundError:\n", + " logging.warning(f\"File not found: {old_name}\")" + ] + }, + { + "cell_type": "markdown", "metadata": {}, + "source": [ + "Over 400,000 protein groups were only identified once (as exactly this group)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "vaep.pandas.counts_with_proportion(pd.Series(c)) # Most proteinGroups are unique" @@ -770,7 +894,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Count genes\n", + "## Count genes\n", "Genes sets could be used to identify common features.\n", "\n", "> The assignment of isoforms to one proteinGroup or another might be volatile.\n", diff --git a/project/erda_02_mq_count_features.py b/project/erda_02_mq_count_features.py index 9e140d55e..ddb60b388 100644 --- a/project/erda_02_mq_count_features.py +++ b/project/erda_02_mq_count_features.py @@ -59,7 +59,7 @@ # # %% -ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml') # acutally MQ txt folders, not files... +ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml') # acutally MQ txt folders, not files... MAP_FOLDER_PATH = Path('config/file_paths.yaml') with open(ELIGABLE_FILES_YAML) as f: @@ -81,6 +81,7 @@ # Select files and create list of folders # %% +files = [file for file in files if file in df_ids.index] folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in files} # folders_dict = {p.stem : p.parent / p.stem for p in folders_dict} # folders_dict @@ -96,7 +97,7 @@ FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES # %% [markdown] -# ## Random example +# ## Random example - peptides # %% pd.set_option('display.max_columns', 60) @@ -175,7 +176,7 @@ f.write("pd.DataFrame.from_records(most_common, index='Sequence', columns=['Sequence', 'counts'])\n") # %% [markdown] Collapsed="false" -# ## Peptides by charge +# ## Random example - precursors # # - count peptides by charge state (which are aggregated in `peptides.txt`) @@ -256,12 +257,21 @@ evidence[evidence_cols.Protein_group_IDs].value_counts() # %% [markdown] -# ## Count peptides based on evidence files +# ## Count precursors based on evidence files # %% evidence_counter = vaep.io.data_objects.EvidenceCounter(FNAME_C_EVIDENCE, overwrite=OVERWRITE) c = evidence_counter.sum_over_files(folders=folders) +# %% +for k, v in tqdm(evidence_counter.dumps.items()): + old_name = v + new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv') + try: + os.rename(old_name, new_name) + except FileNotFoundError: + logging.warning(f"File not found: {old_name}") + # %% [markdown] # ## Protein Groups # @@ -382,17 +392,39 @@ selection.loc[mask] # %% -selection = selection.append(selection_no_gene) +selection = pd.concat([selection, selection_no_gene]) +selection + +# %% [markdown] +# The above is done in the function for loading and processing protein groups + +# %% +vaep.io.data_objects.load_and_process_proteinGroups(random_path) + +# %% [markdown] +# ## Count protein groups (genes) based on proteinGroups files # %% protein_groups_counter = vaep.io.data_objects.ProteinGroupsCounter(FNAME_C_PG, overwrite=OVERWRITE) c = protein_groups_counter.sum_over_files(folders=folders) +# %% +for k, v in tqdm(protein_groups_counter.dumps.items()): + old_name = v + new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv') + try: + os.rename(old_name, new_name) + except FileNotFoundError: + logging.warning(f"File not found: {old_name}") + +# %% [markdown] +# Over 400,000 protein groups were only identified once (as exactly this group). + # %% vaep.pandas.counts_with_proportion(pd.Series(c)) # Most proteinGroups are unique # %% [markdown] -# ### Count genes +# ## Count genes # Genes sets could be used to identify common features. # # > The assignment of isoforms to one proteinGroup or another might be volatile. diff --git a/vaep/io/data_objects.py b/vaep/io/data_objects.py index 23c4f1c71..689e62ae8 100644 --- a/vaep/io/data_objects.py +++ b/vaep/io/data_objects.py @@ -498,7 +498,9 @@ def count_evidence(folders: List[Path], evidence_cols.Protein_group_IDs, evidence_cols.Intensity, evidence_cols.Score, - evidence_cols.Potential_contaminant], + evidence_cols.Potential_contaminant, + evidence_cols.Reverse, + ], parent_folder_fct: Callable = create_parent_folder_name, outfolder=FOLDER_PROCESSED / 'evidence_dumps'): outfolder = Path(outfolder) From 2c78071aaa1505bc7904ffebe684395b6533c019 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Tue, 10 Oct 2023 15:51:26 +0200 Subject: [PATCH 23/70] :bug: methods that give all NA are not filtered - increase robustness of notebook, ignoring all NA methods (here: IMPSEQ) - To consider: should 01_1_train_NAGuideR.ipynb throw an error if all pred are NAs? --- project/01_1_transfer_NAGuideR_pred.ipynb | 13 ++++++++----- project/01_1_transfer_NAGuideR_pred.py | 15 +++++++++------ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/project/01_1_transfer_NAGuideR_pred.ipynb b/project/01_1_transfer_NAGuideR_pred.ipynb index a9eff84b1..5e86f0fa5 100644 --- a/project/01_1_transfer_NAGuideR_pred.ipynb +++ b/project/01_1_transfer_NAGuideR_pred.ipynb @@ -194,18 +194,20 @@ " .drop(test_pred_fake_na.index))\n", "\n", "for fpath in entire_pred:\n", + " logger.info(f\"Load {fpath = }\")\n", " col_name = fpath.stem.split('_all_')[-1]\n", " pred = pd.read_csv(fpath, index_col=[1, 0])\n", " val_pred_fake_na[col_name] = pred\n", " fname = args.out_preds / f'pred_val_{col_name}.csv'\n", " files_out[fname.name] = fname.as_posix()\n", " val_pred_fake_na[['observed', col_name]].to_csv(fname)\n", + " logger.info(f\"Save {fname = }\")\n", "\n", " test_pred_fake_na[col_name] = pred\n", " fname = args.out_preds / f'pred_test_{col_name}.csv'\n", " files_out[fname.name] = fname.as_posix()\n", " test_pred_fake_na[['observed', col_name]].to_csv(fname)\n", - "\n", + " logger.info(f\"Save {fname = }\")\n", " # hacky, but works:\n", " pred_real_na = (pd.Series(0, index=idx_real_na, name='placeholder')\n", " .to_frame()\n", @@ -215,6 +217,7 @@ " fname = args.out_preds / f'pred_real_na_{col_name}.csv'\n", " files_out[fname.name] = fname.as_posix()\n", " pred_real_na.to_csv(fname)\n", + " logger.info(f\"Save {fname = }\")\n", "\n", "# del pred" ] @@ -255,8 +258,8 @@ "metadata": {}, "outputs": [], "source": [ - "added_metrics = d_metrics.add_metrics(val_pred_fake_na, 'valid_fake_na')\n", - "added_metrics" + "added_metrics = d_metrics.add_metrics(val_pred_fake_na.dropna(how='all', axis=1), 'valid_fake_na')\n", + "pd.DataFrame(added_metrics)" ] }, { @@ -274,8 +277,8 @@ "metadata": {}, "outputs": [], "source": [ - "added_metrics = d_metrics.add_metrics(test_pred_fake_na, 'test_fake_na')\n", - "added_metrics" + "added_metrics = d_metrics.add_metrics(test_pred_fake_na.dropna(how='all', axis=1), 'test_fake_na')\n", + "pd.DataFrame(added_metrics)" ] }, { diff --git a/project/01_1_transfer_NAGuideR_pred.py b/project/01_1_transfer_NAGuideR_pred.py index 18058df57..786db0b50 100644 --- a/project/01_1_transfer_NAGuideR_pred.py +++ b/project/01_1_transfer_NAGuideR_pred.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.15.0 +# jupytext_version: 1.15.2 # kernelspec: # display_name: Python 3 # language: python @@ -98,18 +98,20 @@ .drop(test_pred_fake_na.index)) for fpath in entire_pred: + logger.info(f"Load {fpath = }") col_name = fpath.stem.split('_all_')[-1] pred = pd.read_csv(fpath, index_col=[1, 0]) val_pred_fake_na[col_name] = pred fname = args.out_preds / f'pred_val_{col_name}.csv' files_out[fname.name] = fname.as_posix() val_pred_fake_na[['observed', col_name]].to_csv(fname) + logger.info(f"Save {fname = }") test_pred_fake_na[col_name] = pred fname = args.out_preds / f'pred_test_{col_name}.csv' files_out[fname.name] = fname.as_posix() test_pred_fake_na[['observed', col_name]].to_csv(fname) - + logger.info(f"Save {fname = }") # hacky, but works: pred_real_na = (pd.Series(0, index=idx_real_na, name='placeholder') .to_frame() @@ -119,6 +121,7 @@ fname = args.out_preds / f'pred_real_na_{col_name}.csv' files_out[fname.name] = fname.as_posix() pred_real_na.to_csv(fname) + logger.info(f"Save {fname = }") # del pred # %% @@ -132,15 +135,15 @@ d_metrics = vaep.models.Metrics() # %% -added_metrics = d_metrics.add_metrics(val_pred_fake_na, 'valid_fake_na') -added_metrics +added_metrics = d_metrics.add_metrics(val_pred_fake_na.dropna(how='all', axis=1), 'valid_fake_na') +pd.DataFrame(added_metrics) # %% [markdown] # ### Test Datasplit # %% -added_metrics = d_metrics.add_metrics(test_pred_fake_na, 'test_fake_na') -added_metrics +added_metrics = d_metrics.add_metrics(test_pred_fake_na.dropna(how='all', axis=1), 'test_fake_na') +pd.DataFrame(added_metrics) # %% metrics_df = vaep.models.get_df_from_nested_dict( From 8b3ffc86ca126dc281403c07c33defe848f4a891 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Wed, 11 Oct 2023 14:18:55 +0200 Subject: [PATCH 24/70] :art::sparkles: unify and showcase internals, add IDs - function loading and filtering data - add IDs making it possible to make precursors (Evidence IDs), Peptide ID and Protein Groups IDs to each other. in a file the id column is always "id" (e.g. proteinGroups.txt id column = Protein Groups IDs in the other two) --- project/erda_02_mq_count_features.ipynb | 70 +++++++++++++++++-------- project/erda_02_mq_count_features.py | 44 ++++++++++++---- vaep/io/data_objects.py | 55 +++++++++++++------ 3 files changed, 119 insertions(+), 50 deletions(-) diff --git a/project/erda_02_mq_count_features.ipynb b/project/erda_02_mq_count_features.ipynb index 364f6d618..cb7585347 100644 --- a/project/erda_02_mq_count_features.ipynb +++ b/project/erda_02_mq_count_features.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Count peptides over all files" + "# Count and select features of all samples" ] }, { @@ -27,6 +27,7 @@ "\n", "import vaep.pandas\n", "from vaep.io.data_objects import PeptideCounter\n", + "from vaep.io import mq\n", "from vaep.io.mq import MaxQuantOutputDynamic\n", "\n", "##### CONFIG #####\n", @@ -178,20 +179,14 @@ }, "outputs": [], "source": [ - "df_json_string = df.to_json(orient='index', indent=4)\n", - "df_json_string[:1000]" + "mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands" ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], + "cell_type": "markdown", + "metadata": {}, "source": [ - "df_csv = df.to_csv()\n", - "df_csv[:1000]" + "The above is done in the function for loading and processing peptides" ] }, { @@ -202,18 +197,17 @@ }, "outputs": [], "source": [ - "pd.read_json(df_json_string, orient='index')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands" + "# internals: processing file (includes filtering)\n", + "peptides = vaep.io.data_objects.load_process_peptides(random_path,\n", + " use_cols=mq.COLS_ + ['Potential contaminant',\n", + " 'Reverse',\n", + " mq.mq_col.SEQUENCE,\n", + " 'PEP',\n", + " 'id',\n", + " 'Protein group IDs',\n", + " 'Evidence IDs',\n", + " ])\n", + "peptides" ] }, { @@ -519,6 +513,36 @@ "evidence[evidence_cols.Protein_group_IDs].value_counts()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The above is done in the function for loading and processing precursors" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# internals: processing file (includes filtering)\n", + "evidence = vaep.io.data_objects.load_process_evidence(random_path,\n", + " use_cols=[\n", + " mq.mq_evidence_cols.mz,\n", + " mq.mq_evidence_cols.id,\n", + " mq.mq_evidence_cols.Peptide_ID,\n", + " mq.mq_evidence_cols.Protein_group_IDs,\n", + " mq.mq_evidence_cols.Intensity,\n", + " mq.mq_evidence_cols.Score,\n", + " mq.mq_evidence_cols.Potential_contaminant,\n", + " mq.mq_evidence_cols.Reverse],\n", + " select_by='Score')\n", + "evidence" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/project/erda_02_mq_count_features.py b/project/erda_02_mq_count_features.py index ddb60b388..ee0ebe189 100644 --- a/project/erda_02_mq_count_features.py +++ b/project/erda_02_mq_count_features.py @@ -13,7 +13,7 @@ # --- # %% [markdown] -# # Count peptides over all files +# # Count and select features of all samples # %% from collections import Counter @@ -28,6 +28,7 @@ import vaep.pandas from vaep.io.data_objects import PeptideCounter +from vaep.io import mq from vaep.io.mq import MaxQuantOutputDynamic ##### CONFIG ##### @@ -112,18 +113,23 @@ df # %% -df_json_string = df.to_json(orient='index', indent=4) -df_json_string[:1000] +mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands -# %% -df_csv = df.to_csv() -df_csv[:1000] +# %% [markdown] +# The above is done in the function for loading and processing peptides # %% -pd.read_json(df_json_string, orient='index') - -# %% -mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands +# internals: processing file (includes filtering) +peptides = vaep.io.data_objects.load_process_peptides(random_path, + use_cols=mq.COLS_ + ['Potential contaminant', + 'Reverse', + mq.mq_col.SEQUENCE, + 'PEP', + 'id', + 'Protein group IDs', + 'Evidence IDs', + ]) +peptides # %% [markdown] # ## Count aggregated peptides @@ -256,6 +262,24 @@ # %% evidence[evidence_cols.Protein_group_IDs].value_counts() +# %% [markdown] +# The above is done in the function for loading and processing precursors + +# %% +# internals: processing file (includes filtering) +evidence = vaep.io.data_objects.load_process_evidence(random_path, + use_cols=[ + mq.mq_evidence_cols.mz, + mq.mq_evidence_cols.id, + mq.mq_evidence_cols.Peptide_ID, + mq.mq_evidence_cols.Protein_group_IDs, + mq.mq_evidence_cols.Intensity, + mq.mq_evidence_cols.Score, + mq.mq_evidence_cols.Potential_contaminant, + mq.mq_evidence_cols.Reverse], + select_by='Score') +evidence + # %% [markdown] # ## Count precursors based on evidence files diff --git a/vaep/io/data_objects.py b/vaep/io/data_objects.py index 689e62ae8..9dcf988f1 100644 --- a/vaep/io/data_objects.py +++ b/vaep/io/data_objects.py @@ -401,7 +401,26 @@ def __call__(self, folders, # # check df for redundant information (same feature value for all entries) -usecols = mq.COLS_ + ['Potential contaminant', 'Reverse', mq.mq_col.SEQUENCE, 'PEP'] +usecols = mq.COLS_ + ['Potential contaminant', 'Reverse', mq.mq_col.SEQUENCE, 'PEP', + 'id', 'Protein group IDs', 'Evidence IDs',] + + +def select_peptides(peptides: pd.DataFrame) -> pd.DataFrame: + mask = ((peptides[mq.mq_col.INTENSITY] == 0) + | (peptides["Potential contaminant"] == '+') + | (peptides["Reverse"] == '+') + ) + peptides = peptides.loc[~mask] + return peptides + + +def load_process_peptides(folder: Path, use_cols): + peptides = pd.read_table(folder / 'peptides.txt', + usecols=use_cols, + index_col=0, + low_memory=False) + peptides = select_peptides(peptides) + return peptides.drop(['Potential contaminant', 'Reverse'], axis=1) def count_peptides(folders: List[Path], dump=True, @@ -411,20 +430,12 @@ def count_peptides(folders: List[Path], dump=True, c = Counter() fpath_dict = {} for folder in folders: - peptides = pd.read_table(folder / 'peptides.txt', - usecols=usecols, - index_col=0) - mask = ((peptides[mq.mq_col.INTENSITY] == 0) - | (peptides["Potential contaminant"] == '+') - | (peptides["Reverse"] == '+') - ) - peptides = peptides.loc[~mask] + peptides = load_process_peptides(folder, usecols) c.update(peptides.index) if dump: - fpath_dict[folder.stem] = dump_to_csv(peptides.drop( - ['Potential contaminant', 'Reverse'], axis=1), - folder=folder, outfolder=outfolder, - parent_folder_fct=parent_folder_fct) + fpath_dict[folder.stem] = dump_to_csv(peptides, + folder=folder, outfolder=outfolder, + parent_folder_fct=parent_folder_fct) ret = {'counter': c, 'dumps': fpath_dict} return ret @@ -473,7 +484,8 @@ def select_evidence(df_evidence: pd.DataFrame) -> pd.DataFrame: | (df_evidence[evidence_cols.Intensity] == 0) ) evidence = df_evidence.loc[~mask].drop( - evidence_cols.Potential_contaminant, axis=1) + [evidence_cols.Potential_contaminant, + evidence_cols.Reverse], axis=1) evidence = evidence.dropna(subset=[evidence_cols.Intensity]) return evidence @@ -483,7 +495,8 @@ def select_evidence(df_evidence: pd.DataFrame) -> pd.DataFrame: def load_process_evidence(folder: Path, use_cols, select_by): evidence = pd.read_table(folder / 'evidence.txt', - usecols=idx_columns_evidence + use_cols) + usecols=idx_columns_evidence + use_cols, + low_memory=False) evidence = select_evidence(evidence) evidence = vaep.pandas.select_max_by( evidence, grouping_columns=idx_columns_evidence, selection_column=select_by) @@ -495,12 +508,14 @@ def count_evidence(folders: List[Path], select_by: str = 'Score', dump=True, use_cols=[evidence_cols.mz, + evidence_cols.id, + evidence_cols.Peptide_ID, evidence_cols.Protein_group_IDs, evidence_cols.Intensity, evidence_cols.Score, evidence_cols.Potential_contaminant, evidence_cols.Reverse, - ], + ], parent_folder_fct: Callable = create_parent_folder_name, outfolder=FOLDER_PROCESSED / 'evidence_dumps'): outfolder = Path(outfolder) @@ -572,6 +587,7 @@ def load_and_process_proteinGroups(folder: Union[str, Path], use_cols: List = [ pg_cols.Protein_IDs, pg_cols.Majority_protein_IDs, + pg_cols.id, pg_cols.Gene_names, pg_cols.Evidence_IDs, pg_cols.Q_value, @@ -583,7 +599,8 @@ def load_and_process_proteinGroups(folder: Union[str, Path], ]): folder = Path(folder) pg = pd.read_table(folder / 'proteinGroups.txt', - usecols=use_cols) + usecols=use_cols, + low_memory=False) mask = pg[[pg_cols.Only_identified_by_site, pg_cols.Reverse, pg_cols.Potential_contaminant]].notna().any(axis=1) pg = pg.loc[~mask] @@ -601,6 +618,10 @@ def load_and_process_proteinGroups(folder: Union[str, Path], selection_column=pg_cols.Score) pg = pd.concat([pg, pg_no_gene]) pg = pg.set_index(pg_cols.Protein_IDs) + pg = pg.drop([pg_cols.Only_identified_by_site, + pg_cols.Reverse, + pg_cols.Potential_contaminant,], + axis=1) return pg From f53aa966b4fbc3a97c0e34fcbc7f74836c2d5d6f Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Wed, 11 Oct 2023 14:56:12 +0200 Subject: [PATCH 25/70] :art::memo: order by R methods by alphabet, start documenting - tbc: see what works Next: merge with version where parameters for python based models can be set in config.yaml --- .../single_dev_dataset/evidence/config.yaml | 43 ++++++++++--------- .../evidence_N50/config.yaml | 35 +++++++-------- .../single_dev_dataset/peptides/config.yaml | 43 ++++++++++--------- .../peptides_N50/config.yaml | 43 ++++++++++--------- .../proteinGroups/config.yaml | 31 ++++++------- .../proteinGroups_N50/config.yaml | 43 ++++++++++--------- 6 files changed, 122 insertions(+), 116 deletions(-) diff --git a/project/config/single_dev_dataset/evidence/config.yaml b/project/config/single_dev_dataset/evidence/config.yaml index e1b633f67..e92b8d64f 100644 --- a/project/config/single_dev_dataset/evidence/config.yaml +++ b/project/config/single_dev_dataset/evidence/config.yaml @@ -10,24 +10,25 @@ models: - VAE - KNN NAGuideR_methods: - - ZERO - - MINIMUM - - COLMEDIAN - - ROWMEDIAN - - KNN_IMPUTE - # - SEQKNN # error - # - BPCA # stopped after 30mins - # - SVDMETHOD # stopped after 30mins - # - LLS # stopped after 30mins - # - MLE # error - - QRILC - - MINDET - - MINPROB - # - IRM # stopped after 30mins - # - IMPSEQ # error - # - IMPSEQROB # error - # - MICE-NORM # stopped after 30mins - # - MICE-CART # stopped after 30mins - # - TRKNN # error - # - RF # stopped after 30mins - - PI + # - BPCA # stopped after 24h + - COLMEDIAN + - IMPSEQ + - IMPSEQROB + # - IRM # stopped after 24h + # - KNN_IMPUTE + # - LLS # error + # - MICE-CART # stopped after 24h + # - MICE-NORM # stopped after 24h + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - PI + - QRILC + # - RF # stopped after 24h + - ROWMEDIAN + # - SEQKNN # error: Error in x[od, ismiss, drop = FALSE]: subscript out of bounds + - SVDMETHOD + # - TRKNN # stopped after 24h + - ZERO diff --git a/project/config/single_dev_dataset/evidence_N50/config.yaml b/project/config/single_dev_dataset/evidence_N50/config.yaml index cc99984d2..96cb77bfe 100644 --- a/project/config/single_dev_dataset/evidence_N50/config.yaml +++ b/project/config/single_dev_dataset/evidence_N50/config.yaml @@ -10,24 +10,25 @@ models: - VAE - KNN NAGuideR_methods: - - ZERO - - MINIMUM + - BPCA - COLMEDIAN - - ROWMEDIAN + - IMPSEQ + - IMPSEQROB + - IRM # stopped after 24h - KNN_IMPUTE - # - SEQKNN # error - - BPCA - - SVDMETHOD - # - LLS # stopped after 30mins - - MLE - - QRILC # fails for N=10 + - LLS # stopped after 24h + - MICE-CART + - MICE-NORM - MINDET + - MINIMUM - MINPROB - # - IRM # stopped after 30mins - # - IMPSEQ # error - - IMPSEQROB - - MICE-NORM - # - MICE-CART # stopped after 30mins - # - TRKNN # error - # - RF # stopped after 30mins - - PI \ No newline at end of file + - MLE + - MSIMPUTE + - PI + - QRILC + - RF # stopped after 24h + - ROWMEDIAN + - SEQKNN + - SVDMETHOD + - TRKNN # stopped after 24h + - ZERO \ No newline at end of file diff --git a/project/config/single_dev_dataset/peptides/config.yaml b/project/config/single_dev_dataset/peptides/config.yaml index 66bce7a37..3bd4be650 100644 --- a/project/config/single_dev_dataset/peptides/config.yaml +++ b/project/config/single_dev_dataset/peptides/config.yaml @@ -10,24 +10,25 @@ models: - VAE # ~ 3:32 min - KNN # ~ 2:20 min NAGuideR_methods: - - ZERO - - MINIMUM - - COLMEDIAN - - ROWMEDIAN - - KNN_IMPUTE - # - SEQKNN # error - # - BPCA # stopped after 30mins - # - SVDMETHOD # stopped after 30mins - # - LLS # stopped after 30mins - # - MLE # error - - QRILC - - MINDET - - MINPROB - # - IRM # stopped after 30mins - # - IMPSEQ # error - # - IMPSEQROB # error - # - MICE-NORM # stopped after 30mins - # - MICE-CART # stopped after 30mins - # - TRKNN # error - # - RF # stopped after 30mins - - PI + # - BPCA # stopped after 24h + - COLMEDIAN + - IMPSEQ + - IMPSEQROB + # - IRM # stopped after 24h + # - KNN_IMPUTE + # - LLS # error + # - MICE-CART # stopped after 24h + # - MICE-NORM # stopped after 24h + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - PI + - QRILC + # - RF # stopped after 24h + - ROWMEDIAN + # - SEQKNN # error: Error in x[od, ismiss, drop = FALSE]: subscript out of bounds + - SVDMETHOD + # - TRKNN # stopped after 24h + - ZERO diff --git a/project/config/single_dev_dataset/peptides_N50/config.yaml b/project/config/single_dev_dataset/peptides_N50/config.yaml index 0f12e6b0c..8c335a367 100644 --- a/project/config/single_dev_dataset/peptides_N50/config.yaml +++ b/project/config/single_dev_dataset/peptides_N50/config.yaml @@ -11,24 +11,25 @@ models: - VAE - KNN NAGuideR_methods: - - ZERO - - MINIMUM - - COLMEDIAN - - ROWMEDIAN - - KNN_IMPUTE - # - SEQKNN # error - - BPCA - - SVDMETHOD - # - LLS # stopped after 30mins - - MLE - - QRILC # fails for N=10 - - MINDET - - MINPROB - # - IRM # stopped after 30mins - # - IMPSEQ # error - - IMPSEQROB - - MICE-NORM - # - MICE-CART # stopped after 30mins - # - TRKNN # error - # - RF # stopped after 30mins - - PI \ No newline at end of file + - BPCA + - COLMEDIAN + - IMPSEQ + - IMPSEQROB + - IRM + - KNN_IMPUTE + - LLS + - MICE-CART # stopped after 24h + - MICE-NORM # stopped after 24h + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - PI + - QRILC + - RF + - ROWMEDIAN + - SEQKNN + - SVDMETHOD + - TRKNN + - ZERO \ No newline at end of file diff --git a/project/config/single_dev_dataset/proteinGroups/config.yaml b/project/config/single_dev_dataset/proteinGroups/config.yaml index d098ec2e4..a59a936f0 100644 --- a/project/config/single_dev_dataset/proteinGroups/config.yaml +++ b/project/config/single_dev_dataset/proteinGroups/config.yaml @@ -10,24 +10,25 @@ models: - VAE - KNN NAGuideR_methods: - - ZERO - - MINIMUM + - BPCA - COLMEDIAN - - ROWMEDIAN + - IMPSEQ + - IMPSEQROB + - IRM - KNN_IMPUTE - # - SEQKNN # error - # - BPCA # stopped after 30mins - - SVDMETHOD # stopped after 30mins - LLS - # - MLE # error - - QRILC + - MICE-CART # stopped after 24h + - MICE-NORM # stopped after 24h - MINDET + - MINIMUM - MINPROB - # - IRM # stopped after 30mins - # - IMPSEQ # error - # - IMPSEQROB # error - # - MICE-NORM # stopped after 30mins - # - MICE-CART # stopped after 30mins - # - TRKNN # error + - MLE + - MSIMPUTE + - PI + - QRILC - RF - - PI \ No newline at end of file + - ROWMEDIAN + - SEQKNN + - SVDMETHOD + - TRKNN + - ZERO \ No newline at end of file diff --git a/project/config/single_dev_dataset/proteinGroups_N50/config.yaml b/project/config/single_dev_dataset/proteinGroups_N50/config.yaml index 004c4b5aa..3db585591 100644 --- a/project/config/single_dev_dataset/proteinGroups_N50/config.yaml +++ b/project/config/single_dev_dataset/proteinGroups_N50/config.yaml @@ -10,24 +10,25 @@ models: - VAE - KNN NAGuideR_methods: - - ZERO - - MINIMUM - - COLMEDIAN - - ROWMEDIAN - - KNN_IMPUTE - - SEQKNN - - BPCA - - SVDMETHOD - - LLS - - MLE - - QRILC - - MINDET - - MINPROB - - IRM # stopped after 30mins - - IMPSEQ # error - - IMPSEQROB - - MICE-NORM - - MICE-CART # stopped after 30mins - # - TRKNN # error - - RF - - PI + - BPCA + - COLMEDIAN + - IMPSEQ + - IMPSEQROB + - IRM + - KNN_IMPUTE + - LLS + - MICE-CART + - MICE-NORM + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - PI + - QRILC + - RF + - ROWMEDIAN + - SEQKNN + - SVDMETHOD + - TRKNN + - ZERO From 5b3c0b0e88d62ca45094c151802df45788185502 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 12 Oct 2023 15:11:56 +0200 Subject: [PATCH 26/70] :fire: move hela data collection code to new repo -> https://github.com/RasmussenLab/hela_qc_mnt_data commit link: https://github.com/RasmussenLab/hela_qc_mnt_data/commit/f88586bc3988ab8e1dd990187fac4c072719710b - make minor adaption needed due to deletions --- README.md | 15 - project/00_0_0_lftp_upload_commands.ipynb | 610 ---- project/00_0_0_lftp_upload_commands.py | 313 -- project/00_0_1_check_filesizes.ipynb | 396 --- project/00_0_1_check_filesizes.py | 165 -- project/00_0_2_mqout_renaming.ipynb | 165 -- project/00_0_2_mqout_renaming.py | 64 - project/00_0_3_create_sdrf.ipynb | 208 -- project/00_0_3_create_sdrf.py | 127 - project/00_0_4_create_submission_folder.ipynb | 183 -- project/00_0_4_create_submission_folder.py | 80 - project/00_0_hela_metadata_rawfiles.ipynb | 450 --- project/00_0_hela_metadata_rawfiles.py | 219 -- project/00_1_hela_MQ_summaries.ipynb | 201 -- project/00_1_hela_MQ_summaries.py | 106 - project/00_2_hela_all_raw_files.ipynb | 806 ------ project/00_2_hela_all_raw_files.py | 432 --- project/00_3_0_pride_metadata_creation.ipynb | 361 --- project/00_3_0_pride_metadata_creation.py | 165 -- project/00_3_1_pride_metadata_analysis.ipynb | 530 ---- project/00_3_1_pride_metadata_analysis.py | 314 -- project/00_4_development_dataset_support.py | 51 - ...4_hela_development_dataset_splitting.ipynb | 828 ------ ...00_4_hela_development_dataset_splitting.py | 505 ---- .../00_5_development_dataset_support.ipynb | 128 - .../00_6_hela_training_data_exploration.ipynb | 947 ------ .../00_6_hela_training_data_exploration.py | 418 --- project/README.md | 91 - project/config/__init__.py | 226 -- project/config/counter_fpaths.py | 7 - project/config/defaults.py | 17 - project/config/training_data/evidence.py | 18 - project/config/training_data/peptides.py | 19 - project/config/training_data/proteinGroups.py | 20 - project/erda_00_maxquant_file_reader.ipynb | 528 ---- project/erda_00_maxquant_file_reader.py | 266 -- project/erda_01_mq_select_runs.ipynb | 423 --- project/erda_01_mq_select_runs.py | 253 -- project/erda_02_mq_count_features.ipynb | 988 ------- project/erda_02_mq_count_features.py | 479 --- project/erda_03_training_data.ipynb | 396 --- project/erda_03_training_data.py | 232 -- project/erda_04_transpose_file.ipynb | 286 -- project/erda_04_transpose_file.py | 138 - project/erda_05_parse_paramter_files.ipynb | 554 ---- project/erda_05_parse_paramter_files.py | 290 -- project/erda_06_analyze_parameters.ipynb | 153 - project/erda_06_analyze_parameters.py | 59 - project/erda_12_explore_raw_MQ_data.ipynb | 1634 ----------- project/erda_12_explore_raw_MQ_data.py | 840 ------ project/erda_data_available.ipynb | 214 -- project/erda_data_available.py | 91 - project/misc_FASTA_data_agg_by_gene.ipynb | 239 -- project/misc_FASTA_data_agg_by_gene.py | 120 - project/misc_FASTA_tryptic_digest.ipynb | 1281 --------- project/misc_FASTA_tryptic_digest.py | 709 ----- project/misc_MaxQuantOutput.ipynb | 2556 ----------------- project/misc_clustering_proteins.ipynb | 1465 ---------- project/misc_data_exploration_peptides.ipynb | 765 ----- project/misc_data_exploration_proteins.ipynb | 2133 -------------- project/misc_id_mapper.ipynb | 766 ----- project/misc_id_mapper.py | 458 --- project/misc_illustrations.ipynb | 9 +- project/misc_illustrations.py | 6 +- project/misc_protein_support.ipynb | 739 ----- project/src/file_utils.py | 223 -- project/src/setup_logging.py | 9 - vaep/analyzers/analyzers.py | 45 +- vaep/analyzers/metadata.py | 179 -- vaep/databases/__init__.py | 1 - vaep/databases/uniprot.py | 214 -- vaep/fasta.py | 163 -- vaep/io/data_objects.py | 693 ----- vaep/io/filenames.py | 16 - vaep/io/mq.py | 694 ----- vaep/io/rawfiles.py | 116 - vaep/io/thermo_raw_files.py | 25 - vaep/pandas/__init__.py | 49 +- vaep/tests/test_fasta.py | 47 - vaep/tests/test_pandas.py | 24 - vaep/tests/test_utils.py | 5 +- vaep/utils.py | 9 - workflows/README.md | 73 - workflows/hela_files.txt | 552 ---- workflows/maxquant/README.md | 218 -- workflows/maxquant/Snakefile | 194 -- workflows/maxquant/bin/check_current_files.py | 64 - workflows/maxquant/bin/remove_duplicates.py | 44 - workflows/maxquant/computerome2.yaml | 2 - workflows/maxquant/config.yaml | 5 - workflows/maxquant/environment.yml | 11 - workflows/maxquant/mqpar_template_1.5.xml | 234 -- workflows/maxquant/mqpar_template_1.6.xml | 473 --- workflows/maxquant/qsub-status.py | 26 - workflows/maxquant/run_sm_on_cluster.sh | 32 - workflows/maxquant/template_scripts/README.md | 12 - .../template_scripts/mq_job_template.sh | 33 - workflows/maxquant/template_scripts/run_mq.py | 55 - workflows/metadata/.gitignore | 7 - workflows/metadata/README.md | 70 - workflows/metadata/Snakefile | 85 - workflows/metadata/config/README.md | 12 - .../metadata/config/ald_study/config.yaml | 676 ----- .../metadata/config/ald_study/excluded.yaml | 3 - workflows/metadata/config/example.yaml | 8 - workflows/metadata/config/excluded.yaml | 2 - workflows/metadata/read_metadata.ipynb | 314 -- 107 files changed, 22 insertions(+), 33950 deletions(-) delete mode 100644 project/00_0_0_lftp_upload_commands.ipynb delete mode 100644 project/00_0_0_lftp_upload_commands.py delete mode 100644 project/00_0_1_check_filesizes.ipynb delete mode 100644 project/00_0_1_check_filesizes.py delete mode 100644 project/00_0_2_mqout_renaming.ipynb delete mode 100644 project/00_0_2_mqout_renaming.py delete mode 100644 project/00_0_3_create_sdrf.ipynb delete mode 100644 project/00_0_3_create_sdrf.py delete mode 100644 project/00_0_4_create_submission_folder.ipynb delete mode 100644 project/00_0_4_create_submission_folder.py delete mode 100644 project/00_0_hela_metadata_rawfiles.ipynb delete mode 100644 project/00_0_hela_metadata_rawfiles.py delete mode 100644 project/00_1_hela_MQ_summaries.ipynb delete mode 100644 project/00_1_hela_MQ_summaries.py delete mode 100644 project/00_2_hela_all_raw_files.ipynb delete mode 100644 project/00_2_hela_all_raw_files.py delete mode 100644 project/00_3_0_pride_metadata_creation.ipynb delete mode 100644 project/00_3_0_pride_metadata_creation.py delete mode 100644 project/00_3_1_pride_metadata_analysis.ipynb delete mode 100644 project/00_3_1_pride_metadata_analysis.py delete mode 100644 project/00_4_development_dataset_support.py delete mode 100644 project/00_4_hela_development_dataset_splitting.ipynb delete mode 100644 project/00_4_hela_development_dataset_splitting.py delete mode 100644 project/00_5_development_dataset_support.ipynb delete mode 100644 project/00_6_hela_training_data_exploration.ipynb delete mode 100644 project/00_6_hela_training_data_exploration.py delete mode 100644 project/config/__init__.py delete mode 100644 project/config/counter_fpaths.py delete mode 100644 project/config/defaults.py delete mode 100644 project/config/training_data/evidence.py delete mode 100644 project/config/training_data/peptides.py delete mode 100644 project/config/training_data/proteinGroups.py delete mode 100644 project/erda_00_maxquant_file_reader.ipynb delete mode 100644 project/erda_00_maxquant_file_reader.py delete mode 100644 project/erda_01_mq_select_runs.ipynb delete mode 100644 project/erda_01_mq_select_runs.py delete mode 100644 project/erda_02_mq_count_features.ipynb delete mode 100644 project/erda_02_mq_count_features.py delete mode 100644 project/erda_03_training_data.ipynb delete mode 100644 project/erda_03_training_data.py delete mode 100644 project/erda_04_transpose_file.ipynb delete mode 100644 project/erda_04_transpose_file.py delete mode 100644 project/erda_05_parse_paramter_files.ipynb delete mode 100644 project/erda_05_parse_paramter_files.py delete mode 100644 project/erda_06_analyze_parameters.ipynb delete mode 100644 project/erda_06_analyze_parameters.py delete mode 100644 project/erda_12_explore_raw_MQ_data.ipynb delete mode 100644 project/erda_12_explore_raw_MQ_data.py delete mode 100644 project/erda_data_available.ipynb delete mode 100644 project/erda_data_available.py delete mode 100644 project/misc_FASTA_data_agg_by_gene.ipynb delete mode 100644 project/misc_FASTA_data_agg_by_gene.py delete mode 100644 project/misc_FASTA_tryptic_digest.ipynb delete mode 100644 project/misc_FASTA_tryptic_digest.py delete mode 100644 project/misc_MaxQuantOutput.ipynb delete mode 100644 project/misc_clustering_proteins.ipynb delete mode 100644 project/misc_data_exploration_peptides.ipynb delete mode 100644 project/misc_data_exploration_proteins.ipynb delete mode 100644 project/misc_id_mapper.ipynb delete mode 100644 project/misc_id_mapper.py delete mode 100644 project/misc_protein_support.ipynb delete mode 100644 project/src/file_utils.py delete mode 100644 project/src/setup_logging.py delete mode 100644 vaep/analyzers/metadata.py delete mode 100644 vaep/databases/uniprot.py delete mode 100644 vaep/fasta.py delete mode 100644 vaep/io/data_objects.py delete mode 100644 vaep/io/filenames.py delete mode 100644 vaep/io/mq.py delete mode 100644 vaep/io/rawfiles.py delete mode 100644 vaep/io/thermo_raw_files.py delete mode 100644 vaep/tests/test_fasta.py delete mode 100644 workflows/README.md delete mode 100644 workflows/hela_files.txt delete mode 100644 workflows/maxquant/README.md delete mode 100644 workflows/maxquant/Snakefile delete mode 100644 workflows/maxquant/bin/check_current_files.py delete mode 100644 workflows/maxquant/bin/remove_duplicates.py delete mode 100644 workflows/maxquant/computerome2.yaml delete mode 100644 workflows/maxquant/config.yaml delete mode 100644 workflows/maxquant/environment.yml delete mode 100644 workflows/maxquant/mqpar_template_1.5.xml delete mode 100644 workflows/maxquant/mqpar_template_1.6.xml delete mode 100644 workflows/maxquant/qsub-status.py delete mode 100644 workflows/maxquant/run_sm_on_cluster.sh delete mode 100644 workflows/maxquant/template_scripts/README.md delete mode 100644 workflows/maxquant/template_scripts/mq_job_template.sh delete mode 100644 workflows/maxquant/template_scripts/run_mq.py delete mode 100644 workflows/metadata/.gitignore delete mode 100644 workflows/metadata/README.md delete mode 100644 workflows/metadata/Snakefile delete mode 100644 workflows/metadata/config/README.md delete mode 100644 workflows/metadata/config/ald_study/config.yaml delete mode 100644 workflows/metadata/config/ald_study/excluded.yaml delete mode 100644 workflows/metadata/config/example.yaml delete mode 100644 workflows/metadata/config/excluded.yaml delete mode 100644 workflows/metadata/read_metadata.ipynb diff --git a/README.md b/README.md index 04dacdbe6..d6f5f24a9 100644 --- a/README.md +++ b/README.md @@ -227,21 +227,6 @@ From the brief description in the table the exact procedure is not always clear. -## Workflows - -The workflows folder in the repository contains snakemake workflows used for rawfile data processing, -both for running MaxQuant over a large set of HeLa raw files -and ThermoRawFileParser on a list of raw files to extract their meta data. For details see: - -> Webel, Henry, Yasset Perez-Riverol, Annelaura Bach Nielson, and Simon Rasmussen. 2023. “Mass Spectrometry-Based Proteomics Data from Thousands of HeLa Control Samples.” Research Square. https://doi.org/10.21203/rs.3.rs-3083547/v1. - -### MaxQuant - -Process single raw files using MaxQuant. See [README](workflows/maxquant/README.md) for details. - -### Metadata - -Read metadata from single raw files using MaxQuant. See [README](workflows/metadata/README.md) for details. ## Build status [![Documentation Status](https://readthedocs.org/projects/pimms/badge/?version=latest)](https://pimms.readthedocs.io/en/latest/?badge=latest) \ No newline at end of file diff --git a/project/00_0_0_lftp_upload_commands.ipynb b/project/00_0_0_lftp_upload_commands.ipynb deleted file mode 100644 index 3ea94597a..000000000 --- a/project/00_0_0_lftp_upload_commands.ipynb +++ /dev/null @@ -1,610 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "56becfbb-813a-4ea4-b29f-c234b1c45098", - "metadata": {}, - "source": [ - "# Rawfile and MaxQuant output folder renaming\n", - "\n", - "- generated using `workflows/metadata`\n", - "- all raw files collected ~50,000\n", - "- creates lftp upload commands" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0c1cab72-7447-473b-a3d5-1aee8c4815e8", - "metadata": {}, - "outputs": [], - "source": [ - "from pathlib import Path, PurePosixPath\n", - "import pandas as pd\n", - "import yaml\n", - "\n", - "\n", - "def rename(fname, new_sample_id, new_folder=None, ext=None):\n", - " fname = PurePosixPath(fname)\n", - " if ext is None:\n", - " ext = fname.suffix\n", - " if new_folder is None:\n", - " new_folder = fname.parent\n", - " else:\n", - " new_folder = PurePosixPath(new_folder)\n", - " fname = new_folder / new_sample_id\n", - " fname = fname.with_suffix(ext)\n", - " return fname.as_posix()" - ] - }, - { - "cell_type": "markdown", - "id": "d195963d-21b6-4766-a82e-761f31b288bf", - "metadata": {}, - "source": [ - "## Arguments" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7e1629d8-3768-4113-9835-3bed95f219a6", - "metadata": { - "tags": [ - "parameters" - ] - }, - "outputs": [], - "source": [ - "fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' # Machine parsed metadata from rawfile workflow\n", - "fn_mq_summaries: str = 'data/samples_selected_summaries.csv' # MaxQuant summary files\n", - "fn_files_selected: str = 'data/samples_selected.yaml' # selected files based on threshold of identified peptides\n", - "out_folder: str = 'data/rename' # output folder\n", - "fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "06ff016b-f6e0-4cfd-bdd1-fcae5dfc05e9", - "metadata": {}, - "outputs": [], - "source": [ - "out_folder = Path(out_folder)\n", - "out_folder.mkdir(exist_ok=True)\n", - "\n", - "files_out = dict()" - ] - }, - { - "cell_type": "markdown", - "id": "2232196d-7d24-419a-be70-2fac76428eae", - "metadata": {}, - "source": [ - "### Machine metadata\n", - "\n", - "- read from file using [ThermoRawFileParser](https://github.com/compomics/ThermoRawFileParser)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9869ac5e-fab3-4c66-a32c-48ae4fadc0a3", - "metadata": { - "lines_to_next_cell": 2, - "tags": [] - }, - "outputs": [], - "source": [ - "df_meta = pd.read_csv(fn_rawfile_metadata, header=[0, 1], index_col=0, low_memory=False)\n", - "date_col = ('FileProperties', 'Content Creation Date')\n", - "df_meta[date_col] = pd.to_datetime(\n", - " df_meta[date_col])\n", - "df_meta.sort_values(date_col, inplace=True)\n", - "msg = f\"A total of {len(df_meta)} raw files could be read using the ThermoFisherRawFileParser.\"\n", - "print(msg)\n", - "df_meta" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ab1b1bc2-c531-483c-b498-0fb0654bc7dc", - "metadata": {}, - "outputs": [], - "source": [ - "meta_stats = df_meta.describe(include='all')\n", - "meta_stats.T" - ] - }, - { - "cell_type": "markdown", - "id": "a27b9295-47b4-487f-9ef3-84aa2890d843", - "metadata": {}, - "source": [ - "# Erda Paths" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d1c30a7b-fe2e-4a71-a85a-d684cc62ce05", - "metadata": {}, - "outputs": [], - "source": [ - "cols_identifies = [('FileProperties', 'Pathname'),\n", - " ('FileProperties', 'Version'),\n", - " ('FileProperties', 'Content Creation Date'),\n", - " ('InstrumentProperties', 'Thermo Scientific instrument model'),\n", - " ('InstrumentProperties', 'instrument attribute'),\n", - " ('InstrumentProperties', 'instrument serial number'),\n", - " ('InstrumentProperties', 'Software Version'),\n", - " ('InstrumentProperties', 'firmware version'),\n", - " ]\n", - "\n", - "df_meta = df_meta[cols_identifies]\n", - "df_meta.columns = [t[-1] for t in cols_identifies]\n", - "df_meta" - ] - }, - { - "cell_type": "markdown", - "id": "7f61bf7b-3473-487b-b8eb-ac5a6191d507", - "metadata": {}, - "source": [ - "Replace `tmp/` with `./` (artefact)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "17dc5955-3265-4709-a0ec-dc1df505e7d5", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta['Pathname'] = df_meta['Pathname'].str.replace('tmp/', './')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "244501b8-2fbd-461a-844a-5df91b61e18d", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta[\"Instrument_name\"] = (\n", - " df_meta[\"Thermo Scientific instrument model\"].str.replace(' ', '-')\n", - " + '_'\n", - " + df_meta[\"instrument serial number\"].str.split('#').str[-1]\n", - ").str.replace(' ', '-')\n", - "\n", - "df_meta[\"Instrument_name\"].value_counts().index" - ] - }, - { - "cell_type": "markdown", - "id": "6add2fad-2c1c-4542-bcfb-efd1a0ea108f", - "metadata": {}, - "source": [ - "Create new sample identifier" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b42f31ba-e0d5-4afc-8328-f5200213ff85", - "metadata": {}, - "outputs": [], - "source": [ - "date_col = \"Content Creation Date\"\n", - "idx_all = (pd.to_datetime(df_meta[date_col]).dt.strftime(\"%Y_%m_%d_%H_%M\")\n", - " + '_'\n", - " + df_meta[\"Instrument_name\"]\n", - " ).str.replace(' ', '-')\n", - "\n", - "mask = idx_all.duplicated(keep=False)\n", - "duplicated_sample_idx = idx_all.loc[mask].sort_values() # duplicated dumps\n", - "duplicated_sample_idx" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1ddbec78-97bf-4238-9b46-533d20605973", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta['new_sample_id'] = idx_all\n", - "\n", - "\n", - "_n = df_meta.groupby(\"new_sample_id\").cumcount().astype('string').str.replace('0', '')\n", - "_n[_n != ''] = '_r' + _n[_n != '']\n", - "_n.value_counts()\n", - "\n", - "df_meta.loc[mask, \"new_sample_id\"] = df_meta.loc[mask, \"new_sample_id\"] + _n\n", - "\n", - "\n", - "df_meta.loc[mask, [\"Pathname\", \"new_sample_id\"]]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "21962b78-d9c8-4037-aea5-b13e0d5d84ca", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "df_meta.loc[~mask, [\"Pathname\", \"new_sample_id\"]]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d4e0b289-ba7d-4c9b-a08b-c0aafc733855", - "metadata": {}, - "outputs": [], - "source": [ - "assert df_meta[\"Pathname\"].is_unique\n", - "assert df_meta[\"new_sample_id\"].is_unique" - ] - }, - { - "cell_type": "markdown", - "id": "fb446855-eb2f-4000-8c22-a84e58ce8130", - "metadata": {}, - "source": [ - "### Save new paths to disk" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bef2adce-afc7-4698-8aea-4c6415792133", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta[\"Path_old\"] = df_meta[\"Pathname\"]\n", - "\n", - "df_meta[[\"Path_old\", \"new_sample_id\"]]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a67ac714-c966-47ce-8faf-38ca8c94fca7", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta" - ] - }, - { - "cell_type": "markdown", - "id": "3a738dd3-cb4b-4940-bf48-5192186e3614", - "metadata": {}, - "source": [ - "## Selected Files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d630ba07-0674-40b7-b6e9-92a34f4e4788", - "metadata": {}, - "outputs": [], - "source": [ - "with open(fn_files_selected) as f:\n", - " files_selected = yaml.safe_load(f)\n", - "print(f'Threshold: {files_selected[\"threshold\"]:,d}')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c2204d45-20b5-4b24-8af1-04614769b275", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta.loc[files_selected[\"files\"]]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f79366bc-38ba-415b-bccf-0a842241ca03", - "metadata": {}, - "outputs": [], - "source": [ - "mask = idx_all.duplicated()\n", - "selected = df_meta.loc[~mask].index.intersection(files_selected[\"files\"])\n", - "df_meta.loc[selected]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ccb44ce0-253c-485b-8533-f6716e9855d3", - "metadata": {}, - "outputs": [], - "source": [ - "def build_instrument_name(s):\n", - " \"\"\"Process in order, only keep one name\"\"\"\n", - " ret = ''\n", - " used_before = set()\n", - " for string_w_withspaces in s:\n", - " strings_ = string_w_withspaces.split()\n", - " for string_ in strings_:\n", - " if string_ not in used_before:\n", - " ret += f'_{string_}'\n", - " used_before |= set(strings_)\n", - " ret = (ret[1:] # remove _ from start\n", - " .replace('Slot_#', '')\n", - " .replace('slot_#', '')\n", - " )\n", - " return ret\n", - "\n", - "\n", - "(df_meta[\n", - " [\n", - " \"Thermo Scientific instrument model\",\n", - " \"instrument attribute\",\n", - " \"instrument serial number\",\n", - " ]\n", - "]\n", - " .sample(20)\n", - " .apply(build_instrument_name, axis=1)\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d1a3d03d-e79d-4cb3-9f9e-7b415060f38b", - "metadata": {}, - "outputs": [], - "source": [ - "fname = out_folder / 'selected_old_new_id_mapping.csv'\n", - "files_out[fname.name] = fname.as_posix()\n", - "df_meta.loc[selected].to_csv(fname)\n", - "fname" - ] - }, - { - "cell_type": "markdown", - "id": "b0c69dd0-53a5-480e-a7cc-bb43b49a09cb", - "metadata": {}, - "source": [ - "### OS rename" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "801ccc99-a0f6-44bb-9605-5cf01cf57d21", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta.loc[selected][[\"Path_old\", \"new_sample_id\"]]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "447c9308", - "metadata": {}, - "outputs": [], - "source": [ - "(df_meta\n", - " .loc[selected, \"Path_old\"]\n", - " .iloc[:3]\n", - " .to_csv(out_folder / 'rawfiles_to_checksum.txt',\n", - " index=False,\n", - " header=False)\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "f07d1e53-f017-4d61-970d-3eb4ca2905c5", - "metadata": {}, - "source": [ - "Save summaries for selected files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "62c3084e", - "metadata": {}, - "outputs": [], - "source": [ - "df_summaries = pd.read_csv(fn_mq_summaries, index_col=0)\n", - "df_summaries = df_summaries.loc[selected].rename(df_meta.loc[selected, 'new_sample_id'])\n", - "df_summaries.to_csv(out_folder / 'mq_summaries.csv')\n", - "del df_summaries" - ] - }, - { - "cell_type": "markdown", - "id": "556a7087", - "metadata": {}, - "source": [ - "## Put files on PRgIDE FTP server\n", - "\n", - "rename using `new_sample_id`" - ] - }, - { - "cell_type": "markdown", - "id": "c9f014ce-8efc-48a0-9779-435385dfc792", - "metadata": {}, - "source": [ - "### LFTP commands - raw files\n", - "\n", - "`-f` option allows to pass commands from a file\n", - "One needs to at least an `open` as the first line to log in to an ftp server\n", - "For pride one needs to additionally `cd` to the correct folder:\n", - "```bash\n", - "> open ...\n", - "> cd ...\n", - "```\n", - "to allow parallell commands, use the runtime setting\n", - "```bash\n", - ">>> cat ~/.lftprc\n", - "set cmd:parallel 2\n", - "```" - ] - }, - { - "cell_type": "markdown", - "id": "8d5998e4", - "metadata": {}, - "source": [ - "Create folders on pride for raw files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "080b3773", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta[\"folder_raw\"] = \"./raw_files/\" + df_meta[\"Instrument_name\"]\n", - "df_meta[\"folder_raw\"].unique()\n", - "\n", - "fname = out_folder / 'raw_file_directories.txt'\n", - "\n", - "commands = 'mkdir -p ' + df_meta.loc[selected, \"folder_raw\"].drop_duplicates()\n", - "commands.to_csv(fname, header=False, index=False)" - ] - }, - { - "cell_type": "markdown", - "id": "1a124d24", - "metadata": {}, - "source": [ - "Create upload commands of raw files to create folders (could be combined with above)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "790c66e2-1a1e-46e2-9fd9-5ad7b86fc793", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "commands = df_meta.loc[selected]\n", - "commands = (\n", - " 'put '\n", - " + commands['Path_old'].astype('string')\n", - " + ' -o '\n", - " + \"./raw_files/\"\n", - " + commands[\"Instrument_name\"]\n", - " + '/'\n", - " + commands['new_sample_id'] + '.raw'\n", - ")\n", - "print(commands.sample(10).to_csv(sep=' ', header=False, index=False))" - ] - }, - { - "cell_type": "markdown", - "id": "b8a6ebb2", - "metadata": {}, - "source": [ - "write all to file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9d1263b3", - "metadata": {}, - "outputs": [], - "source": [ - "fname = out_folder / 'lftp_commands_rawfiles.txt'\n", - "commands.to_csv(fname, header=False, index=False)" - ] - }, - { - "cell_type": "markdown", - "id": "bddf9902-71fe-4b86-930e-ced060d867ff", - "metadata": {}, - "source": [ - "### LFTP commands - MaxQuant output" - ] - }, - { - "cell_type": "markdown", - "id": "2b6faff1-92a4-46ff-a14f-f6fb241265d7", - "metadata": {}, - "source": [ - "Create upload commands of MaxQuant output folders to pride using mirror\n", - "\n", - "- `mq_out` folder\n", - "- move from `Sample ID` folder into `new_sample_id` on erda" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d60b149d-d32a-4d97-b908-1c778a58a224", - "metadata": {}, - "outputs": [], - "source": [ - "commands = df_meta.loc[selected]\n", - "commands = (\n", - " \"mirror -R --only-missing --log log_lftp_mirror.log --exclude-glob *.pdf \" # command\n", - " + \"mq_out/\" + commands.index # source\n", - " + \" ./MQ_tables/\" + commands[\"Instrument_name\"] + \"/\" + commands[\"new_sample_id\"] # dest\n", - ")\n", - "\n", - "print(commands.sample(10).to_csv(header=False, index=False))" - ] - }, - { - "cell_type": "markdown", - "id": "6989ded5", - "metadata": {}, - "source": [ - "write all to file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "83c04b90-0c4e-4fe7-88f6-ed02cef93a23", - "metadata": {}, - "outputs": [], - "source": [ - "fname = out_folder / 'lftp_commands_mq_output.txt'\n", - "commands.to_csv(fname, header=False, index=False)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/00_0_0_lftp_upload_commands.py b/project/00_0_0_lftp_upload_commands.py deleted file mode 100644 index 03b71f264..000000000 --- a/project/00_0_0_lftp_upload_commands.py +++ /dev/null @@ -1,313 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: Python 3 -# language: python -# name: python3 -# --- - -# %% [markdown] -# # Rawfile and MaxQuant output folder renaming -# -# - generated using `workflows/metadata` -# - all raw files collected ~50,000 -# - creates lftp upload commands - -# %% -from pathlib import Path, PurePosixPath -import pandas as pd -import yaml - - -def rename(fname, new_sample_id, new_folder=None, ext=None): - fname = PurePosixPath(fname) - if ext is None: - ext = fname.suffix - if new_folder is None: - new_folder = fname.parent - else: - new_folder = PurePosixPath(new_folder) - fname = new_folder / new_sample_id - fname = fname.with_suffix(ext) - return fname.as_posix() - - -# %% [markdown] -# ## Arguments - -# %% tags=["parameters"] -fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' # Machine parsed metadata from rawfile workflow -fn_mq_summaries: str = 'data/samples_selected_summaries.csv' # MaxQuant summary files -fn_files_selected: str = 'data/samples_selected.yaml' # selected files based on threshold of identified peptides -out_folder: str = 'data/rename' # output folder -fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files - -# %% -out_folder = Path(out_folder) -out_folder.mkdir(exist_ok=True) - -files_out = dict() - -# %% [markdown] -# ### Machine metadata -# -# - read from file using [ThermoRawFileParser](https://github.com/compomics/ThermoRawFileParser) - -# %% -df_meta = pd.read_csv(fn_rawfile_metadata, header=[0, 1], index_col=0, low_memory=False) -date_col = ('FileProperties', 'Content Creation Date') -df_meta[date_col] = pd.to_datetime( - df_meta[date_col]) -df_meta.sort_values(date_col, inplace=True) -msg = f"A total of {len(df_meta)} raw files could be read using the ThermoFisherRawFileParser." -print(msg) -df_meta - - -# %% -meta_stats = df_meta.describe(include='all') -meta_stats.T - -# %% [markdown] -# # Erda Paths - -# %% -cols_identifies = [('FileProperties', 'Pathname'), - ('FileProperties', 'Version'), - ('FileProperties', 'Content Creation Date'), - ('InstrumentProperties', 'Thermo Scientific instrument model'), - ('InstrumentProperties', 'instrument attribute'), - ('InstrumentProperties', 'instrument serial number'), - ('InstrumentProperties', 'Software Version'), - ('InstrumentProperties', 'firmware version'), - ] - -df_meta = df_meta[cols_identifies] -df_meta.columns = [t[-1] for t in cols_identifies] -df_meta - -# %% [markdown] -# Replace `tmp/` with `./` (artefact) - -# %% -df_meta['Pathname'] = df_meta['Pathname'].str.replace('tmp/', './') - -# %% -df_meta["Instrument_name"] = ( - df_meta["Thermo Scientific instrument model"].str.replace(' ', '-') - + '_' - + df_meta["instrument serial number"].str.split('#').str[-1] -).str.replace(' ', '-') - -df_meta["Instrument_name"].value_counts().index - -# %% [markdown] -# Create new sample identifier - -# %% -date_col = "Content Creation Date" -idx_all = (pd.to_datetime(df_meta[date_col]).dt.strftime("%Y_%m_%d_%H_%M") - + '_' - + df_meta["Instrument_name"] - ).str.replace(' ', '-') - -mask = idx_all.duplicated(keep=False) -duplicated_sample_idx = idx_all.loc[mask].sort_values() # duplicated dumps -duplicated_sample_idx - -# %% -df_meta['new_sample_id'] = idx_all - - -_n = df_meta.groupby("new_sample_id").cumcount().astype('string').str.replace('0', '') -_n[_n != ''] = '_r' + _n[_n != ''] -_n.value_counts() - -df_meta.loc[mask, "new_sample_id"] = df_meta.loc[mask, "new_sample_id"] + _n - - -df_meta.loc[mask, ["Pathname", "new_sample_id"]] - -# %% -df_meta.loc[~mask, ["Pathname", "new_sample_id"]] - - -# %% -assert df_meta["Pathname"].is_unique -assert df_meta["new_sample_id"].is_unique - -# %% [markdown] -# ### Save new paths to disk - -# %% -df_meta["Path_old"] = df_meta["Pathname"] - -df_meta[["Path_old", "new_sample_id"]] - -# %% -df_meta - -# %% [markdown] -# ## Selected Files - -# %% -with open(fn_files_selected) as f: - files_selected = yaml.safe_load(f) -print(f'Threshold: {files_selected["threshold"]:,d}') - -# %% -df_meta.loc[files_selected["files"]] - -# %% -mask = idx_all.duplicated() -selected = df_meta.loc[~mask].index.intersection(files_selected["files"]) -df_meta.loc[selected] - - -# %% -def build_instrument_name(s): - """Process in order, only keep one name""" - ret = '' - used_before = set() - for string_w_withspaces in s: - strings_ = string_w_withspaces.split() - for string_ in strings_: - if string_ not in used_before: - ret += f'_{string_}' - used_before |= set(strings_) - ret = (ret[1:] # remove _ from start - .replace('Slot_#', '') - .replace('slot_#', '') - ) - return ret - - -(df_meta[ - [ - "Thermo Scientific instrument model", - "instrument attribute", - "instrument serial number", - ] -] - .sample(20) - .apply(build_instrument_name, axis=1) -) - -# %% -fname = out_folder / 'selected_old_new_id_mapping.csv' -files_out[fname.name] = fname.as_posix() -df_meta.loc[selected].to_csv(fname) -fname - -# %% [markdown] -# ### OS rename - -# %% -df_meta.loc[selected][["Path_old", "new_sample_id"]] - -# %% -(df_meta - .loc[selected, "Path_old"] - .iloc[:3] - .to_csv(out_folder / 'rawfiles_to_checksum.txt', - index=False, - header=False) - ) - -# %% [markdown] -# Save summaries for selected files - -# %% -df_summaries = pd.read_csv(fn_mq_summaries, index_col=0) -df_summaries = df_summaries.loc[selected].rename(df_meta.loc[selected, 'new_sample_id']) -df_summaries.to_csv(out_folder / 'mq_summaries.csv') -del df_summaries - -# %% [markdown] -# ## Put files on PRgIDE FTP server -# -# rename using `new_sample_id` - -# %% [markdown] -# ### LFTP commands - raw files -# -# `-f` option allows to pass commands from a file -# One needs to at least an `open` as the first line to log in to an ftp server -# For pride one needs to additionally `cd` to the correct folder: -# ```bash -# > open ... -# > cd ... -# ``` -# to allow parallell commands, use the runtime setting -# ```bash -# >>> cat ~/.lftprc -# set cmd:parallel 2 -# ``` - -# %% [markdown] -# Create folders on pride for raw files - -# %% -df_meta["folder_raw"] = "./raw_files/" + df_meta["Instrument_name"] -df_meta["folder_raw"].unique() - -fname = out_folder / 'raw_file_directories.txt' - -commands = 'mkdir -p ' + df_meta.loc[selected, "folder_raw"].drop_duplicates() -commands.to_csv(fname, header=False, index=False) - -# %% [markdown] -# Create upload commands of raw files to create folders (could be combined with above) - -# %% -commands = df_meta.loc[selected] -commands = ( - 'put ' - + commands['Path_old'].astype('string') - + ' -o ' - + "./raw_files/" - + commands["Instrument_name"] - + '/' - + commands['new_sample_id'] + '.raw' -) -print(commands.sample(10).to_csv(sep=' ', header=False, index=False)) - - -# %% [markdown] -# write all to file - -# %% -fname = out_folder / 'lftp_commands_rawfiles.txt' -commands.to_csv(fname, header=False, index=False) - -# %% [markdown] -# ### LFTP commands - MaxQuant output - -# %% [markdown] -# Create upload commands of MaxQuant output folders to pride using mirror -# -# - `mq_out` folder -# - move from `Sample ID` folder into `new_sample_id` on erda - -# %% -commands = df_meta.loc[selected] -commands = ( - "mirror -R --only-missing --log log_lftp_mirror.log --exclude-glob *.pdf " # command - + "mq_out/" + commands.index # source - + " ./MQ_tables/" + commands["Instrument_name"] + "/" + commands["new_sample_id"] # dest -) - -print(commands.sample(10).to_csv(header=False, index=False)) - -# %% [markdown] -# write all to file - -# %% -fname = out_folder / 'lftp_commands_mq_output.txt' -commands.to_csv(fname, header=False, index=False) diff --git a/project/00_0_1_check_filesizes.ipynb b/project/00_0_1_check_filesizes.ipynb deleted file mode 100644 index 549a0b1ef..000000000 --- a/project/00_0_1_check_filesizes.ipynb +++ /dev/null @@ -1,396 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "f581713e", - "metadata": {}, - "source": [ - "# Check if filesizes of local and uploaded files match\n", - "- could be replaced with checksums, but it's too slow on erda\n", - "- instead: compare if filesizes in bytes more or less match (tolerance of 5 bytes)\n", - "\n", - "many things could be refactored in case a tool should be created from this" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e3e033c1", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "from collections import namedtuple\n", - "from pathlib import Path, PurePosixPath\n", - "import pandas as pd" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7ad76c5a", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "# Parameters\n", - "FOLDER = Path('data/rename')\n", - "fname_mq_out_pride = FOLDER / 'mq_out_filesizes_pride.log'\n", - "fname_mq_out_erda = FOLDER / 'mq_out_filesizes_erda.log'\n", - "fname_rawfiles_pride = FOLDER / 'rawfiles_filesizes_pride.log'\n", - "fname_rawfiles_erda = FOLDER / 'rawfiles_filesizes_erda.log'\n", - "fname_filenames_mapping = FOLDER / 'selected_old_new_id_mapping.csv'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eb2fab6a", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta = pd.read_csv(fname_filenames_mapping, index_col='Path_old')\n", - "df_meta" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1f1a85ce", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta['path_pride'] = 'raw_files/' + df_meta['Instrument_name'] + '/' + df_meta[\"new_sample_id\"] + '.raw'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cd5f1ae0", - "metadata": {}, - "outputs": [], - "source": [ - "entries = list()\n", - "Entry = namedtuple('Entry', 'size_erda fname name_erda')\n", - "with open(fname_rawfiles_erda) as f:\n", - " for line in f:\n", - " size, fname = line.strip().split('\\t')\n", - " fname = PurePosixPath(fname)\n", - " if fname.suffix:\n", - " entry = Entry(int(size), str(fname).replace('share_hela_raw/', './'), fname.name)\n", - " if entry.fname in df_meta.index:\n", - " entries.append(entry)\n", - "print(f\"{len(entries) =: }\")\n", - "entries[:3]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0494dd62", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "entries = pd.DataFrame(entries).set_index('fname')\n", - "entries = (entries\n", - " .join(df_meta.loc[entries.index, 'path_pride'])\n", - " .reset_index()\n", - " .set_index('path_pride')\n", - " .sort_index())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "27b0c5ff", - "metadata": {}, - "outputs": [], - "source": [ - "entries_pride = list()\n", - "Entry = namedtuple('Entry', ['size_pride', 'path_pride', 'name_pride', 'instrument'])\n", - "with open(fname_rawfiles_pride) as f:\n", - " for line in f:\n", - " size, fname = line.strip().split()\n", - " fname = PurePosixPath(fname)\n", - " if fname.suffix:\n", - " entry = Entry(int(size), str(fname), fname.name, fname.parent.name)\n", - " entries_pride.append(entry)\n", - "print(f\"{len(entries_pride) =: }\")\n", - "entries_pride[:3]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "507995c3", - "metadata": {}, - "outputs": [], - "source": [ - "entries_pride = pd.DataFrame(entries_pride).set_index('path_pride').sort_index()\n", - "entries_pride" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b37640f7", - "metadata": {}, - "outputs": [], - "source": [ - "entries = entries.join(entries_pride, on='path_pride', how='left')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "720feda4", - "metadata": {}, - "outputs": [], - "source": [ - "mask = (entries['size_pride'] - entries['size_erda']).abs() > 5\n", - "to_redo = entries.loc[mask].reset_index()\n", - "to_redo" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8aff71d9", - "metadata": {}, - "outputs": [], - "source": [ - "commands = 'put ' + to_redo['fname'] + ' -o ' + to_redo['path_pride']\n", - "print(commands.to_csv(header=False, index=False))" - ] - }, - { - "cell_type": "markdown", - "id": "b6087751", - "metadata": {}, - "source": [ - "## Check MaxQuant output filesizes" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4290a2b6", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "df_meta = df_meta.reset_index().set_index('Sample ID')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a32ac1ba", - "metadata": {}, - "outputs": [], - "source": [ - "files = list()\n", - "folder = set()\n", - "Entry = namedtuple('Entry', 'size_erda path_erda id_old filename')\n", - "with open(fname_mq_out_erda) as f:\n", - " for line in f:\n", - " size, fname = line.strip().split('\\t')\n", - " fname = PurePosixPath(fname)\n", - " if fname.suffix and fname.suffix != '.pdf':\n", - " entry = Entry(int(size), str(fname), fname.parent.name, fname.name)\n", - " if entry.id_old in df_meta.index:\n", - " files.append(entry)\n", - " if entry.id_old not in folder:\n", - " folder.add(entry.id_old)\n", - "\n", - "print(f\"{len(folder) =: }\")\n", - "print(f\"{len(files) =: }\")\n", - "files[:3]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d63f458a", - "metadata": {}, - "outputs": [], - "source": [ - "files = pd.DataFrame(files).set_index('id_old')\n", - "files = files.join(df_meta[['Instrument_name', 'new_sample_id']])\n", - "files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "082e1cc9", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "files['path_pride'] = ('MQ_tables/'\n", - " + files['Instrument_name']\n", - " + '/'\n", - " + files[\"new_sample_id\"]\n", - " + '/'\n", - " + files[\"filename\"])\n", - "files['path_pride'].iloc[:4].to_list()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4a27d1e1", - "metadata": {}, - "outputs": [], - "source": [ - "files['filename'].value_counts() # except mqpar.xml all present on erda" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "111c6607", - "metadata": {}, - "outputs": [], - "source": [ - "files_pride = list()\n", - "Entry = namedtuple('Entry', ['size_pride', 'path_pride', 'id_new', 'instrument'])\n", - "with open(fname_mq_out_pride) as f:\n", - " for line in f:\n", - " size, fname = line.strip().split('\\t')\n", - " fname = PurePosixPath(fname)\n", - " if fname.suffix:\n", - " entry = Entry(int(size), str(fname), fname.parent.name, fname.parent.parent.name)\n", - " files_pride.append(entry)\n", - "print(f\"{len(files_pride) =: }\")\n", - "files_pride[:3]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b7776e97", - "metadata": { - "lines_to_next_cell": 0 - }, - "outputs": [], - "source": [ - "files_pride = pd.DataFrame(files_pride).set_index('path_pride')\n", - "files_pride" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d82d3a19", - "metadata": { - "lines_to_next_cell": 0 - }, - "outputs": [], - "source": [ - "files = files.set_index('path_pride').join(files_pride, how='left')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "93722b9a", - "metadata": { - "lines_to_next_cell": 0 - }, - "outputs": [], - "source": [ - "missing_on_pride = files.loc[files['size_pride'].isna()]\n", - "missing_on_pride" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "42059238", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "missing_on_pride['filename'].value_counts()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "466e2ba8", - "metadata": { - "lines_to_next_cell": 0 - }, - "outputs": [], - "source": [ - "files['size_diff'] = files['size_pride'] - files['size_erda']\n", - "files['size_diff'].abs().describe()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f7e03424", - "metadata": {}, - "outputs": [], - "source": [ - "files_redo = files.loc[files['size_diff'].abs() > 5]\n", - "files_redo" - ] - }, - { - "cell_type": "markdown", - "id": "59bbd393", - "metadata": {}, - "source": [ - "ensure quoted paths as they might contain whitespaces" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3fc22aef", - "metadata": {}, - "outputs": [], - "source": [ - "to_do = pd.concat([missing_on_pride, files_redo])\n", - "commands = 'put -e \\'' + to_do['path_erda'] + \"' -o '\" + to_do.index + \"'\"\n", - "commands.to_csv(FOLDER / 'mq_out_remaining.txt', header=False, index=False)" - ] - } - ], - "metadata": { - "jupytext": { - "cell_metadata_filter": "-all", - "notebook_metadata_filter": "-all" - }, - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/00_0_1_check_filesizes.py b/project/00_0_1_check_filesizes.py deleted file mode 100644 index e8df8a58a..000000000 --- a/project/00_0_1_check_filesizes.py +++ /dev/null @@ -1,165 +0,0 @@ -# %% [markdown] -# # Check if filesizes of local and uploaded files match -# - could be replaced with checksums, but it's too slow on erda -# - instead: compare if filesizes in bytes more or less match (tolerance of 5 bytes) -# -# many things could be refactored in case a tool should be created from this - -# %% -from collections import namedtuple -from pathlib import Path, PurePosixPath -import pandas as pd - - -# %% -# Parameters -FOLDER = Path('data/rename') -fname_mq_out_pride = FOLDER / 'mq_out_filesizes_pride.log' -fname_mq_out_erda = FOLDER / 'mq_out_filesizes_erda.log' -fname_rawfiles_pride = FOLDER / 'rawfiles_filesizes_pride.log' -fname_rawfiles_erda = FOLDER / 'rawfiles_filesizes_erda.log' -fname_filenames_mapping = FOLDER / 'selected_old_new_id_mapping.csv' - - -# %% -df_meta = pd.read_csv(fname_filenames_mapping, index_col='Path_old') -df_meta - -# %% -df_meta['path_pride'] = 'raw_files/' + df_meta['Instrument_name'] + '/' + df_meta["new_sample_id"] + '.raw' - -# %% -entries = list() -Entry = namedtuple('Entry', 'size_erda fname name_erda') -with open(fname_rawfiles_erda) as f: - for line in f: - size, fname = line.strip().split('\t') - fname = PurePosixPath(fname) - if fname.suffix: - entry = Entry(int(size), str(fname).replace('share_hela_raw/', './'), fname.name) - if entry.fname in df_meta.index: - entries.append(entry) -print(f"{len(entries) =: }") -entries[:3] - -# %% -entries = pd.DataFrame(entries).set_index('fname') -entries = (entries - .join(df_meta.loc[entries.index, 'path_pride']) - .reset_index() - .set_index('path_pride') - .sort_index()) - - -# %% -entries_pride = list() -Entry = namedtuple('Entry', ['size_pride', 'path_pride', 'name_pride', 'instrument']) -with open(fname_rawfiles_pride) as f: - for line in f: - size, fname = line.strip().split() - fname = PurePosixPath(fname) - if fname.suffix: - entry = Entry(int(size), str(fname), fname.name, fname.parent.name) - entries_pride.append(entry) -print(f"{len(entries_pride) =: }") -entries_pride[:3] - -# %% -entries_pride = pd.DataFrame(entries_pride).set_index('path_pride').sort_index() -entries_pride - -# %% -entries = entries.join(entries_pride, on='path_pride', how='left') - -# %% -mask = (entries['size_pride'] - entries['size_erda']).abs() > 5 -to_redo = entries.loc[mask].reset_index() -to_redo - -# %% -commands = 'put ' + to_redo['fname'] + ' -o ' + to_redo['path_pride'] -print(commands.to_csv(header=False, index=False)) - -# %% [markdown] -# ## Check MaxQuant output filesizes - -# %% -df_meta = df_meta.reset_index().set_index('Sample ID') - - -# %% -files = list() -folder = set() -Entry = namedtuple('Entry', 'size_erda path_erda id_old filename') -with open(fname_mq_out_erda) as f: - for line in f: - size, fname = line.strip().split('\t') - fname = PurePosixPath(fname) - if fname.suffix and fname.suffix != '.pdf': - entry = Entry(int(size), str(fname), fname.parent.name, fname.name) - if entry.id_old in df_meta.index: - files.append(entry) - if entry.id_old not in folder: - folder.add(entry.id_old) - -print(f"{len(folder) =: }") -print(f"{len(files) =: }") -files[:3] - -# %% -files = pd.DataFrame(files).set_index('id_old') -files = files.join(df_meta[['Instrument_name', 'new_sample_id']]) -files - -# %% -files['path_pride'] = ('MQ_tables/' - + files['Instrument_name'] - + '/' - + files["new_sample_id"] - + '/' - + files["filename"]) -files['path_pride'].iloc[:4].to_list() - - -# %% -files['filename'].value_counts() # except mqpar.xml all present on erda - -# %% -files_pride = list() -Entry = namedtuple('Entry', ['size_pride', 'path_pride', 'id_new', 'instrument']) -with open(fname_mq_out_pride) as f: - for line in f: - size, fname = line.strip().split('\t') - fname = PurePosixPath(fname) - if fname.suffix: - entry = Entry(int(size), str(fname), fname.parent.name, fname.parent.parent.name) - files_pride.append(entry) -print(f"{len(files_pride) =: }") -files_pride[:3] - -# %% -files_pride = pd.DataFrame(files_pride).set_index('path_pride') -files_pride -# %% -files = files.set_index('path_pride').join(files_pride, how='left') -# %% -missing_on_pride = files.loc[files['size_pride'].isna()] -missing_on_pride -# %% -missing_on_pride['filename'].value_counts() - - -# %% -files['size_diff'] = files['size_pride'] - files['size_erda'] -files['size_diff'].abs().describe() -# %% -files_redo = files.loc[files['size_diff'].abs() > 5] -files_redo - -# %% [markdown] -# ensure quoted paths as they might contain whitespaces - -# %% -to_do = pd.concat([missing_on_pride, files_redo]) -commands = 'put -e \'' + to_do['path_erda'] + "' -o '" + to_do.index + "'" -commands.to_csv(FOLDER / 'mq_out_remaining.txt', header=False, index=False) diff --git a/project/00_0_2_mqout_renaming.ipynb b/project/00_0_2_mqout_renaming.ipynb deleted file mode 100644 index e32643f4b..000000000 --- a/project/00_0_2_mqout_renaming.ipynb +++ /dev/null @@ -1,165 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "349432fa", - "metadata": {}, - "source": [ - "# Rename file names in MaxQuant output files\n", - "renaming the folder of outputs does not delete all occurences of the names\n", - "in the text files. This needs to be done manually by the PRIDE team using a shell script\n", - "that uses `sed` to replace the old names with the new ones.\n", - "\n", - "uses the list of output as stored on pride dropbox server and meta data of old and new name" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8a10bc6a", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "from collections import defaultdict\n", - "from pathlib import Path, PurePosixPath\n", - "import pandas as pd" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "614edb34", - "metadata": {}, - "outputs": [], - "source": [ - "FOLDER = Path('data/rename')\n", - "meta_in = FOLDER / 'selected_old_new_id_mapping.csv'\n", - "fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d67125f5", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta = pd.read_csv(meta_in, index_col='new_sample_id')\n", - "df_meta" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f1acf13f", - "metadata": { - "title": "[makrdown]" - }, - "outputs": [], - "source": [ - "# ## Create commands to rename file names in text files itself\n", - "# - only subset of files contain original file names on exection of MaxQuant" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e700c55f", - "metadata": {}, - "outputs": [], - "source": [ - "files_types = [\"modificationSpecificPeptides.txt\",\n", - " \"mqpar.xml\",\n", - " \"mzRange.txt\",\n", - " \"Oxidation (M)Sites.txt\",\n", - " \"summary.txt\",]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c31e15b", - "metadata": {}, - "outputs": [], - "source": [ - "name_lookup = df_meta[\"Sample ID\"].reset_index().set_index(\"new_sample_id\")\n", - "name_lookup" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4fff3884", - "metadata": {}, - "outputs": [], - "source": [ - "to_rename = list()\n", - "command_template = 'sed -i \"s/{old_name}/{new_name}/g\" \"{fn}\"'\n", - "counter = defaultdict(int)\n", - "\n", - "with open(fn_server_log) as f:\n", - " for line in f:\n", - " fname = PurePosixPath(line.strip())\n", - " if fname.name in files_types:\n", - " new_name = fname.parent.name\n", - " old_name = name_lookup.loc[new_name, 'Sample ID']\n", - " command = command_template.format(old_name=old_name,\n", - " new_name=new_name,\n", - " fn=fname)\n", - " to_rename.append(command)\n", - "\n", - " counter[fname.name] += 1\n", - "len(to_rename)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "87426e9a", - "metadata": {}, - "outputs": [], - "source": [ - "# mqpar.xml missing in some folders\n", - "pd.Series(counter) # maybe one folder has some missing?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "46727631", - "metadata": {}, - "outputs": [], - "source": [ - "with open(FOLDER / 'sed_rename_commands.sh', 'w') as f:\n", - " f.writelines('\\n'.join(to_rename))" - ] - } - ], - "metadata": { - "jupytext": { - "cell_metadata_filter": "title,-all", - "notebook_metadata_filter": "-all" - }, - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/00_0_2_mqout_renaming.py b/project/00_0_2_mqout_renaming.py deleted file mode 100644 index 0a223751f..000000000 --- a/project/00_0_2_mqout_renaming.py +++ /dev/null @@ -1,64 +0,0 @@ -# %% [markdown] -# # Rename file names in MaxQuant output files -# renaming the folder of outputs does not delete all occurences of the names -# in the text files. This needs to be done manually by the PRIDE team using a shell script -# that uses `sed` to replace the old names with the new ones. -# -# uses the list of output as stored on pride dropbox server and meta data of old and new name - -# %% -from collections import defaultdict -from pathlib import Path, PurePosixPath -import pandas as pd - - -# %% -FOLDER = Path('data/rename') -meta_in = FOLDER / 'selected_old_new_id_mapping.csv' -fn_server_log: str = 'data/rename/mq_out_server.log' # server log of all uploaded files - -# %% -df_meta = pd.read_csv(meta_in, index_col='new_sample_id') -df_meta - -# %% [makrdown] -# ## Create commands to rename file names in text files itself -# - only subset of files contain original file names on exection of MaxQuant - -# %% -files_types = ["modificationSpecificPeptides.txt", - "mqpar.xml", - "mzRange.txt", - "Oxidation (M)Sites.txt", - "summary.txt",] - -# %% -name_lookup = df_meta["Sample ID"].reset_index().set_index("new_sample_id") -name_lookup - -# %% -to_rename = list() -command_template = 'sed -i "s/{old_name}/{new_name}/g" "{fn}"' -counter = defaultdict(int) - -with open(fn_server_log) as f: - for line in f: - fname = PurePosixPath(line.strip()) - if fname.name in files_types: - new_name = fname.parent.name - old_name = name_lookup.loc[new_name, 'Sample ID'] - command = command_template.format(old_name=old_name, - new_name=new_name, - fn=fname) - to_rename.append(command) - - counter[fname.name] += 1 -len(to_rename) - -# %% -# mqpar.xml missing in some folders -pd.Series(counter) # maybe one folder has some missing? - -# %% -with open(FOLDER / 'sed_rename_commands.sh', 'w') as f: - f.writelines('\n'.join(to_rename)) diff --git a/project/00_0_3_create_sdrf.ipynb b/project/00_0_3_create_sdrf.ipynb deleted file mode 100644 index eec8de40d..000000000 --- a/project/00_0_3_create_sdrf.ipynb +++ /dev/null @@ -1,208 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "da553f6b", - "metadata": {}, - "source": [ - "# Create SDRF file\n", - "- [example](https://github.com/bigbio/proteomics-sample-metadata/blob/6f31044f0bcf545ae2da6e853f8ccad011ea4703/annotated-projects/PXD000895/PXD000895.sdrf.tsv)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "85a2d719", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "from pathlib import Path\n", - "import pandas as pd" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2e9e102d", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "fn_sdrf_cellline_template = Path('data') / 'sdrf-cell-line-template.tsv'\n", - "fn_meta = Path('data/rename') / 'selected_old_new_id_mapping.csv'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8426e2f1", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta = pd.read_csv(fn_meta, index_col='new_sample_id')\n", - "df_meta" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6712b0d9", - "metadata": { - "lines_to_next_cell": 0 - }, - "outputs": [], - "source": [ - "sdrf = pd.DataFrame() # pd.read_table(fn_sdrf_cellline_template)\n", - "sdrf['source name'] = df_meta.index\n", - "sdrf = sdrf.set_index('source name')\n", - "sdrf['characteristics[organism]'] = 'Homo sapiens'\n", - "sdrf['characteristics[organism part]'] = 'cervex'\n", - "sdrf['characteristics[ancestry category]'] = 'Black'\n", - "sdrf['characteristics[age]'] = '31Y'\n", - "sdrf['characteristics[developmental stage]'] = 'adult'\n", - "sdrf['characteristics[sex]'] = 'female'\n", - "sdrf['characteristics[cell line]'] = 'HeLa cells'\n", - "sdrf['characteristics[cell type]'] = 'epithelial'\n", - "sdrf['characteristics[disease]'] = 'adenocarcinoma'\n", - "sdrf['characteristics[cell line]'] = 'HeLa cells'\n", - "sdrf['characteristics[biological replicate]'] = 1\n", - "sdrf['assay name'] = sdrf.index\n", - "sdrf['technology type'] = 'proteomic profiling by mass spectrometer'\n", - "sdrf['comment[technical replicate]'] = range(0, len(sdrf))\n", - "sdrf['comment[data file]'] = sdrf.index + '.raw'\n", - "sdrf['comment[fraction identifier]'] = 1\n", - "sdrf['comment[label]'] = 'NT=label free sample;AC=MS:1002038' # To check\n", - "sdrf['comment[cleavage agent details]'] = 'NT=Trypsin;AC=MS:1001251'\n", - "sdrf['comment[instrument]'] = df_meta['Instrument_name']\n", - "\n", - "sdrf" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c14ca4f0", - "metadata": {}, - "outputs": [], - "source": [ - "# based on https://www.ebi.ac.uk/ols4/\n", - "#\n", - "# Q Exactive HF-X MS:1002877\n", - "# Q Exactive HF MS:1002523\n", - "# Orbitrap Exploris 480 MS:1003028\n", - "# Exactive Plus MS:1002526\n", - "# Q Exactive MS:1001911\n", - "# Orbitrap Fusion Lumos MS:1002732\n", - "\n", - "\n", - "instrument_ms_mapping = {\n", - " 'Q-Exactive-HF-X-Orbitrap_6070': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-X-Orbitrap_6071': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-X-Orbitrap_6075': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-X-Orbitrap_6101': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-Orbitrap_207': 'NT=Q Exactive HF;AC=MS:1002523',\n", - " 'Q-Exactive-HF-X-Orbitrap_6096': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-X-Orbitrap_6078': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-Orbitrap_147': 'NT=Q Exactive HF;AC=MS:1002523',\n", - " 'Q-Exactive-Orbitrap_1': 'NT=Q Exactive;AC=MS:1001911',\n", - " 'Q-Exactive-HF-Orbitrap_143': 'NT=Q Exactive HF;AC=MS:1002523',\n", - " 'Q-Exactive-HF-Orbitrap_204': 'NT=Q Exactive HF;AC=MS:1002523',\n", - " 'Q-Exactive-HF-X-Orbitrap_6011': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-Orbitrap_206': 'NT=Q Exactive HF;AC=MS:1002523',\n", - " 'Q-Exactive-HF-X-Orbitrap_6073': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-Orbitrap_1': 'NT=Q Exactive HF;AC=MS:1002523',\n", - " 'Q-Exactive-HF-Orbitrap_148': 'NT=Q Exactive HF;AC=MS:1002523',\n", - " 'Orbitrap-Fusion-Lumos_FSN20115': 'NT=Orbitrap Fusion Lumos;AC=MS:1002732',\n", - " 'Q-Exactive-HF-X-Orbitrap_6016': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-X-Orbitrap_6004': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Orbitrap-Exploris-480_MA10132C': 'NT=Orbitrap Exploris 480;AC=MS:1003028',\n", - " 'Q-Exactive-HF-X-Orbitrap_6028': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-X-Orbitrap_6044': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-X-Orbitrap_6025': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-X-Orbitrap_6324': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Orbitrap-Exploris-480_MA10134C': 'NT=Orbitrap Exploris 480;AC=MS:1003028',\n", - " 'Q-Exactive-HF-X-Orbitrap_6022': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-X-Orbitrap_6043': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-X-Orbitrap_6013': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Q-Exactive-HF-X-Orbitrap_6023': 'NT=Q Exactive HF-X;AC=MS:1002877:',\n", - " 'Exactive-Series-Orbitrap_6004': 'NT=Q Exactive;AC=MS:1001911',\n", - " 'Orbitrap-Exploris-480_Invalid_SN_0001': 'NT=Orbitrap Exploris 480;AC=MS:1003028',\n", - " 'Orbitrap-Exploris-480_MA10215C': 'NT=Orbitrap Exploris 480;AC=MS:1003028',\n", - " 'Q-Exactive-HF-Orbitrap_2612': 'NT=Q Exactive HF;AC=MS:1002523',\n", - " 'Q-Exactive-Plus-Orbitrap_1': 'NT=Exactive Plus;AC=MS:1002526',\n", - " 'Q-Exactive-Plus-Orbitrap_143': 'NT=Exactive Plus;AC=MS:1002526',\n", - " 'Orbitrap-Exploris-480_MA10130C': 'NT=Orbitrap Exploris 480;AC=MS:1003028',\n", - "}\n", - "sdrf['comment[instrument]'] = sdrf['comment[instrument]'].replace(\n", - " instrument_ms_mapping)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "57c38cb7", - "metadata": {}, - "outputs": [], - "source": [ - "# change order: The column `technology type`` cannot be before the `assay name`` -- ERROR\n", - "# template has wrong order (open PR)\n", - "# -> done now above\n", - "# order = ['characteristics[organism]',\n", - "# 'characteristics[organism part]',\n", - "# 'characteristics[ancestry category]',\n", - "# 'characteristics[cell type]',\n", - "# 'characteristics[disease]',\n", - "# 'characteristics[cell line]',\n", - "# 'characteristics[biological replicate]',\n", - "# 'assay name',\n", - "# 'technology type',\n", - "# 'comment[technical replicate]',\n", - "# 'comment[data file]',\n", - "# 'comment[fraction identifier]',\n", - "# 'comment[label]',\n", - "# 'comment[cleavage agent details]',\n", - "# 'comment[instrument]']\n", - "\n", - "# sdrf = sdrf[order]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d81cff5f", - "metadata": { - "lines_to_next_cell": 0 - }, - "outputs": [], - "source": [ - "fname = Path('data') / 'dev_datasets' / 'Experimental-Design.sdrf.tsv'\n", - "sdrf.to_csv(fname, sep='\\t')\n", - "fname" - ] - }, - { - "cell_type": "markdown", - "id": "b80c5166", - "metadata": {}, - "source": [ - "## Validate SDRF file\n", - "```\n", - "pip install sdrf-pipelines\n", - "parse_sdrf validate-sdrf --sdrf_file project\\data\\dev_datasets\\sdrf.tsv\n", - "```" - ] - } - ], - "metadata": { - "jupytext": { - "cell_metadata_filter": "-all", - "main_language": "python", - "notebook_metadata_filter": "-all" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/00_0_3_create_sdrf.py b/project/00_0_3_create_sdrf.py deleted file mode 100644 index dd6d5178b..000000000 --- a/project/00_0_3_create_sdrf.py +++ /dev/null @@ -1,127 +0,0 @@ -# %% [markdown] -# # Create SDRF file -# - [example](https://github.com/bigbio/proteomics-sample-metadata/blob/6f31044f0bcf545ae2da6e853f8ccad011ea4703/annotated-projects/PXD000895/PXD000895.sdrf.tsv) - -# %% -from pathlib import Path -import pandas as pd - - -# %% -fn_sdrf_cellline_template = Path('data') / 'sdrf-cell-line-template.tsv' -fn_meta = Path('data/rename') / 'selected_old_new_id_mapping.csv' - - -# %% -df_meta = pd.read_csv(fn_meta, index_col='new_sample_id') -df_meta - -# %% -sdrf = pd.DataFrame() # pd.read_table(fn_sdrf_cellline_template) -sdrf['source name'] = df_meta.index -sdrf = sdrf.set_index('source name') -sdrf['characteristics[organism]'] = 'Homo sapiens' -sdrf['characteristics[organism part]'] = 'cervex' -sdrf['characteristics[ancestry category]'] = 'Black' -sdrf['characteristics[age]'] = '31Y' -sdrf['characteristics[developmental stage]'] = 'adult' -sdrf['characteristics[sex]'] = 'female' -sdrf['characteristics[cell line]'] = 'HeLa cells' -sdrf['characteristics[cell type]'] = 'epithelial' -sdrf['characteristics[disease]'] = 'adenocarcinoma' -sdrf['characteristics[cell line]'] = 'HeLa cells' -sdrf['characteristics[biological replicate]'] = 1 -sdrf['assay name'] = sdrf.index -sdrf['technology type'] = 'proteomic profiling by mass spectrometer' -sdrf['comment[technical replicate]'] = range(0, len(sdrf)) -sdrf['comment[data file]'] = sdrf.index + '.raw' -sdrf['comment[fraction identifier]'] = 1 -sdrf['comment[label]'] = 'NT=label free sample;AC=MS:1002038' # To check -sdrf['comment[cleavage agent details]'] = 'NT=Trypsin;AC=MS:1001251' -sdrf['comment[instrument]'] = df_meta['Instrument_name'] - -sdrf -# %% -# based on https://www.ebi.ac.uk/ols4/ -# -# Q Exactive HF-X MS:1002877 -# Q Exactive HF MS:1002523 -# Orbitrap Exploris 480 MS:1003028 -# Exactive Plus MS:1002526 -# Q Exactive MS:1001911 -# Orbitrap Fusion Lumos MS:1002732 - - -instrument_ms_mapping = { - 'Q-Exactive-HF-X-Orbitrap_6070': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-X-Orbitrap_6071': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-X-Orbitrap_6075': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-X-Orbitrap_6101': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-Orbitrap_207': 'NT=Q Exactive HF;AC=MS:1002523', - 'Q-Exactive-HF-X-Orbitrap_6096': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-X-Orbitrap_6078': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-Orbitrap_147': 'NT=Q Exactive HF;AC=MS:1002523', - 'Q-Exactive-Orbitrap_1': 'NT=Q Exactive;AC=MS:1001911', - 'Q-Exactive-HF-Orbitrap_143': 'NT=Q Exactive HF;AC=MS:1002523', - 'Q-Exactive-HF-Orbitrap_204': 'NT=Q Exactive HF;AC=MS:1002523', - 'Q-Exactive-HF-X-Orbitrap_6011': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-Orbitrap_206': 'NT=Q Exactive HF;AC=MS:1002523', - 'Q-Exactive-HF-X-Orbitrap_6073': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-Orbitrap_1': 'NT=Q Exactive HF;AC=MS:1002523', - 'Q-Exactive-HF-Orbitrap_148': 'NT=Q Exactive HF;AC=MS:1002523', - 'Orbitrap-Fusion-Lumos_FSN20115': 'NT=Orbitrap Fusion Lumos;AC=MS:1002732', - 'Q-Exactive-HF-X-Orbitrap_6016': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-X-Orbitrap_6004': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Orbitrap-Exploris-480_MA10132C': 'NT=Orbitrap Exploris 480;AC=MS:1003028', - 'Q-Exactive-HF-X-Orbitrap_6028': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-X-Orbitrap_6044': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-X-Orbitrap_6025': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-X-Orbitrap_6324': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Orbitrap-Exploris-480_MA10134C': 'NT=Orbitrap Exploris 480;AC=MS:1003028', - 'Q-Exactive-HF-X-Orbitrap_6022': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-X-Orbitrap_6043': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-X-Orbitrap_6013': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Q-Exactive-HF-X-Orbitrap_6023': 'NT=Q Exactive HF-X;AC=MS:1002877:', - 'Exactive-Series-Orbitrap_6004': 'NT=Q Exactive;AC=MS:1001911', - 'Orbitrap-Exploris-480_Invalid_SN_0001': 'NT=Orbitrap Exploris 480;AC=MS:1003028', - 'Orbitrap-Exploris-480_MA10215C': 'NT=Orbitrap Exploris 480;AC=MS:1003028', - 'Q-Exactive-HF-Orbitrap_2612': 'NT=Q Exactive HF;AC=MS:1002523', - 'Q-Exactive-Plus-Orbitrap_1': 'NT=Exactive Plus;AC=MS:1002526', - 'Q-Exactive-Plus-Orbitrap_143': 'NT=Exactive Plus;AC=MS:1002526', - 'Orbitrap-Exploris-480_MA10130C': 'NT=Orbitrap Exploris 480;AC=MS:1003028', -} -sdrf['comment[instrument]'] = sdrf['comment[instrument]'].replace( - instrument_ms_mapping) - -# %% -# change order: The column `technology type`` cannot be before the `assay name`` -- ERROR -# template has wrong order (open PR) -# -> done now above -# order = ['characteristics[organism]', -# 'characteristics[organism part]', -# 'characteristics[ancestry category]', -# 'characteristics[cell type]', -# 'characteristics[disease]', -# 'characteristics[cell line]', -# 'characteristics[biological replicate]', -# 'assay name', -# 'technology type', -# 'comment[technical replicate]', -# 'comment[data file]', -# 'comment[fraction identifier]', -# 'comment[label]', -# 'comment[cleavage agent details]', -# 'comment[instrument]'] - -# sdrf = sdrf[order] - -# %% -fname = Path('data') / 'dev_datasets' / 'Experimental-Design.sdrf.tsv' -sdrf.to_csv(fname, sep='\t') -fname -# %% [markdown] -# ## Validate SDRF file -# ``` -# pip install sdrf-pipelines -# parse_sdrf validate-sdrf --sdrf_file project\data\dev_datasets\sdrf.tsv -# ``` diff --git a/project/00_0_4_create_submission_folder.ipynb b/project/00_0_4_create_submission_folder.ipynb deleted file mode 100644 index 59360c84f..000000000 --- a/project/00_0_4_create_submission_folder.ipynb +++ /dev/null @@ -1,183 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "5466db14", - "metadata": { - "lines_to_next_cell": 2 - }, - "source": [ - "# Submission file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "74dcae2a", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "from collections import defaultdict\n", - "from pathlib import Path, PurePosixPath" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5e780185", - "metadata": {}, - "outputs": [], - "source": [ - "# Parameters\n", - "FOLDER = Path('data/rename')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b5c99d62", - "metadata": {}, - "outputs": [], - "source": [ - "file = FOLDER / 'files_on_pride.log'\n", - "# file = FOLDER / 'files_pride_server_toplevel.log'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2f71d21a", - "metadata": {}, - "outputs": [], - "source": [ - "counts = defaultdict(int)\n", - "with open(file) as f:\n", - " for line in f:\n", - " fname = line.strip()\n", - " suffix = PurePosixPath(fname).suffix\n", - " counts[suffix] += 1\n", - "dict(counts)" - ] - }, - { - "cell_type": "markdown", - "id": "2f18e74e", - "metadata": {}, - "source": [ - "Only create a few files for creation a submission.px template...\n", - "\n", - "# %%\n", - "SUBMISSON_FOLDER = Path('data/rename/submission')\n", - "SUBMISSON_FOLDER.mkdir(exist_ok=True)\n", - "with open(file) as f:\n", - " hash = 'placeholder'\n", - " for line in f:\n", - " # fname = line.strip().split()\n", - " fname = line.strip()\n", - " fname = PurePosixPath(fname).name\n", - " with open(SUBMISSON_FOLDER / fname, 'w') as f_out:\n", - " f_out.write(f'{hash} {fname}')\n", - "# %%\n", - "files = list(SUBMISSON_FOLDER.iterdir())\n", - "print(f\"{len(files) = :,d}\")" - ] - }, - { - "cell_type": "markdown", - "id": "80f86e6a", - "metadata": {}, - "source": [ - "7444 raw files\n", - "7444 zip files with MaxQuant results\n", - "3 zip files with aggregated MaxQuant results\n", - "1 SDRF file as tsv\n", - "2 csv files with metadata of the raw files and the MaxQuant results summaries" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "91903d5e", - "metadata": {}, - "outputs": [], - "source": [ - "# len(files) == 7444*2 + 6 # expected number of files" - ] - }, - { - "cell_type": "markdown", - "id": "64114469", - "metadata": {}, - "source": [ - "This was not really necessary..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5d8ccc0f", - "metadata": {}, - "outputs": [], - "source": [ - "file_types = {'.zip': 'SEARCH',\n", - " '.raw': 'RAW',\n", - " '.csv': 'SEARCH',\n", - " '.tsv': 'EXPERIMENTAL_DESIGN'}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "92389c3b", - "metadata": { - "lines_to_next_cell": 0 - }, - "outputs": [], - "source": [ - "files = pd.DataFrame(columns='FMH\tfile_id\tfile_type\tfile_path\tfile_mapping'.split('\\t'))\n", - "files['file_path'] = pd.read_csv(file, header=None)\n", - "files['FMH'] = 'FMH'\n", - "files['file_id'] = files.index\n", - "files['file_type'] = files['file_path'].map(lambda x: file_types[Path(x).suffix])\n", - "files['file_mapping'] = files['file_id'] - 1\n", - "files.loc[\n", - " files['file_type'] != 'SEARCH', 'file_mapping'] = np.nan\n", - "files = files.astype({'file_id': int, 'file_mapping': pd.Int32Dtype()})\n", - "files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "249d011d", - "metadata": { - "lines_to_next_cell": 0 - }, - "outputs": [], - "source": [ - "files.to_csv(FOLDER / 'submiss.px_to_add.tsv', sep='\\t', index=False)" - ] - }, - { - "cell_type": "markdown", - "id": "9107e219", - "metadata": {}, - "source": [ - "Some manuel adding of the last files still required..." - ] - } - ], - "metadata": { - "jupytext": { - "cell_metadata_filter": "-all", - "main_language": "python", - "notebook_metadata_filter": "-all" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/00_0_4_create_submission_folder.py b/project/00_0_4_create_submission_folder.py deleted file mode 100644 index 91ad14fdf..000000000 --- a/project/00_0_4_create_submission_folder.py +++ /dev/null @@ -1,80 +0,0 @@ -# %% [markdown] -# # Submission file - - -# %% -import pandas as pd -import numpy as np -from collections import defaultdict -from pathlib import Path, PurePosixPath - - -# %% -# Parameters -FOLDER = Path('data/rename') - -# %% -file = FOLDER / 'files_on_pride.log' -# file = FOLDER / 'files_pride_server_toplevel.log' - -# %% -counts = defaultdict(int) -with open(file) as f: - for line in f: - fname = line.strip() - suffix = PurePosixPath(fname).suffix - counts[suffix] += 1 -dict(counts) - -# %% [markdown] -# Only create a few files for creation a submission.px template... -# -# # %% -# SUBMISSON_FOLDER = Path('data/rename/submission') -# SUBMISSON_FOLDER.mkdir(exist_ok=True) -# with open(file) as f: -# hash = 'placeholder' -# for line in f: -# # fname = line.strip().split() -# fname = line.strip() -# fname = PurePosixPath(fname).name -# with open(SUBMISSON_FOLDER / fname, 'w') as f_out: -# f_out.write(f'{hash} {fname}') -# # %% -# files = list(SUBMISSON_FOLDER.iterdir()) -# print(f"{len(files) = :,d}") - -# %% [markdown] -# 7444 raw files -# 7444 zip files with MaxQuant results -# 3 zip files with aggregated MaxQuant results -# 1 SDRF file as tsv -# 2 csv files with metadata of the raw files and the MaxQuant results summaries - -# %% -# len(files) == 7444*2 + 6 # expected number of files - -# %% [markdown] -# This was not really necessary... - -# %% -file_types = {'.zip': 'SEARCH', - '.raw': 'RAW', - '.csv': 'SEARCH', - '.tsv': 'EXPERIMENTAL_DESIGN'} - -# %% -files = pd.DataFrame(columns='FMH file_id file_type file_path file_mapping'.split('\t')) -files['file_path'] = pd.read_csv(file, header=None) -files['FMH'] = 'FMH' -files['file_id'] = files.index -files['file_type'] = files['file_path'].map(lambda x: file_types[Path(x).suffix]) -files['file_mapping'] = files['file_id'] - 1 -files.loc[ - files['file_type'] != 'SEARCH', 'file_mapping'] = np.nan -files = files.astype({'file_id': int, 'file_mapping': pd.Int32Dtype()}) -files -# %% -files.to_csv(FOLDER / 'submiss.px_to_add.tsv', sep='\t', index=False) -# %% [markdown] -# Some manuel adding of the last files still required... diff --git a/project/00_0_hela_metadata_rawfiles.ipynb b/project/00_0_hela_metadata_rawfiles.ipynb deleted file mode 100644 index b4ca77ca5..000000000 --- a/project/00_0_hela_metadata_rawfiles.ipynb +++ /dev/null @@ -1,450 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "8d7f70a2-ce2b-450c-ad95-9e2c879cbdae", - "metadata": {}, - "source": [ - "# Rawfile metadata\n", - "\n", - "- generated using `workflows/metadata`\n", - "- all raw files collected ~50,000" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "18bc909e-536b-430d-984e-ddf45cf16726", - "metadata": {}, - "outputs": [], - "source": [ - "from collections import namedtuple\n", - "from collections import defaultdict\n", - "\n", - "import yaml\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "import vaep.pandas" - ] - }, - { - "cell_type": "markdown", - "id": "3ce6c1cc-6ffc-411c-b3e4-8780939028e0", - "metadata": {}, - "source": [ - "## Arguments" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "204776e0-5693-4621-8380-4e127f3fe290", - "metadata": { - "tags": [ - "parameters" - ] - }, - "outputs": [], - "source": [ - "fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' # Machine parsed metadata from rawfile workflow\n", - "# outputs\n", - "# All parsed raw files nested by instrument (model, attribute, serial number)\n", - "fn_files_per_instrument: str = 'data/files_per_instrument.yaml'\n", - "fn_files_selected: str = 'data/samples_selected.yaml' # selected files based on threshold of identified peptides\n", - "# Selected parsed raw files nested by instrument (model, attribute, serial number)\n", - "fn_files_per_instrument_selected: str = 'data/files_selected_per_instrument.yaml'" - ] - }, - { - "cell_type": "markdown", - "id": "f1ff9c99-9162-4a53-99c5-b5691ee0b12a", - "metadata": {}, - "source": [ - "### Machine metadata\n", - "\n", - "- read from file using [ThermoRawFileParser](https://github.com/compomics/ThermoRawFileParser)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "39c2b9ea-2524-4bbd-9780-127873a2c18b", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "df_meta_rawfiles = pd.read_csv(fn_rawfile_metadata, header=[0, 1], index_col=0, low_memory=False)\n", - "date_col = ('FileProperties', 'Content Creation Date')\n", - "df_meta_rawfiles[date_col] = pd.to_datetime(\n", - " df_meta_rawfiles[date_col])\n", - "df_meta_rawfiles.sort_values(date_col, inplace=True)\n", - "df_meta_rawfiles" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "32b42511", - "metadata": {}, - "outputs": [], - "source": [ - "msg = f\"A total of {len(df_meta_rawfiles)} raw files could be read using the ThermoFisherRawFileParser.\"\n", - "print(msg)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "083e076f-f584-4236-9b9c-0bbd1dfa34bf", - "metadata": {}, - "outputs": [], - "source": [ - "meta_stats = df_meta_rawfiles.describe(include='all')\n", - "meta_stats.T" - ] - }, - { - "cell_type": "markdown", - "id": "0b3ef962-fe95-4af7-9d8e-4427a5950a78", - "metadata": {}, - "source": [ - "subset with variation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5f63f93e-4bbf-4445-80c4-de7a11fe3fee", - "metadata": {}, - "outputs": [], - "source": [ - "meta_stats.loc[:, (meta_stats.loc['unique'] > 1) | (meta_stats.loc['std'] > 0.1)].T" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "abc0cef2-e8d1-4178-b6ea-e073cc9bcd8a", - "metadata": {}, - "outputs": [], - "source": [ - "# needs to go to Config which is not overwriteable by attribute selection\n", - "df_meta_rawfiles_columns = df_meta_rawfiles.columns\n", - "meta_raw_names = df_meta_rawfiles.columns.droplevel()\n", - "assert meta_raw_names.is_unique\n", - "df_meta_rawfiles.columns = meta_raw_names\n", - "df_meta_rawfiles" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2fe29d9e-a7af-4bc1-95c0-67c492431ed1", - "metadata": {}, - "outputs": [], - "source": [ - "meta_raw_selected = [\n", - " 'Content Creation Date',\n", - " 'Thermo Scientific instrument model',\n", - " 'instrument serial number',\n", - " 'Software Version',\n", - " 'Number of MS1 spectra',\n", - " 'Number of MS2 spectra',\n", - " 'Number of scans',\n", - " 'MS max charge',\n", - " 'MS max RT',\n", - " 'MS min MZ',\n", - " 'MS max MZ',\n", - " 'MS scan range',\n", - " 'mass resolution',\n", - " 'Retention time range',\n", - " 'Mz range',\n", - " 'beam-type collision-induced dissociation',\n", - " 'injection volume setting',\n", - " 'dilution factor',\n", - "]\n", - "df_meta_rawfiles[meta_raw_selected].describe(percentiles=np.linspace(0.05, 0.95, 10))" - ] - }, - { - "cell_type": "markdown", - "id": "ab323148-8af6-4ca8-99dc-0c5e9ef86714", - "metadata": {}, - "source": [ - "- `MS min MZ`: outlier clearly shifts means\n", - "- `mass resolution` is unique (can this be?)\n", - "- `dillution factor` is unique (can this be?)" - ] - }, - { - "cell_type": "markdown", - "id": "7a34bb67-6e9b-4f6f-a79c-c953afc0aa4d", - "metadata": {}, - "source": [ - "## Instrument type and settings\n", - "\n", - "check some columns describing settings\n", - " - quite some variation due to `MS max charge`: Is it a parameter?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9accd23f-06f5-47ef-b9fd-110fbdb12752", - "metadata": {}, - "outputs": [], - "source": [ - "MetaRawSettings = namedtuple(\n", - " 'MetaRawSettings',\n", - " 'ms_model ms_attr ms_sn ms_firmware max_charge mass_res cid_type inject_volume dill_factor')\n", - "meta_raw_settings = [\n", - " 'Thermo Scientific instrument model',\n", - " 'instrument attribute',\n", - " 'instrument serial number',\n", - " 'Software Version',\n", - " 'MS max charge',\n", - " 'mass resolution',\n", - " 'beam-type collision-induced dissociation',\n", - " 'injection volume setting',\n", - " 'dilution factor',\n", - "]\n", - "meta_raw_settings = MetaRawSettings(*meta_raw_settings)\n", - "meta_raw_settings" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9a7cbb3b-f97c-42c2-a094-4842d9b722dd", - "metadata": {}, - "outputs": [], - "source": [ - "# index gives first example with this combination\n", - "# df_meta_rawfiles[list(meta_raw_settings)].drop_duplicates()\n", - "df_meta_rawfiles[list(meta_raw_settings)].drop_duplicates(ignore_index=True)" - ] - }, - { - "cell_type": "markdown", - "id": "50f85fa8-a0c5-4c4b-b292-22721989c21a", - "metadata": {}, - "source": [ - "view without `MS max charge`:\n", - " - software can be updated\n", - " - variation by `injection volume setting` and instrument over time\n", - " - missing `dilution factor`\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "35682fcc-503c-444f-ace9-4d50a1726ca3", - "metadata": {}, - "outputs": [], - "source": [ - "to_drop = ['MS max charge']\n", - "# df_meta_rawfiles[list(meta_raw_settings)].drop(to_drop,\n", - "# axis=1).drop_duplicates(ignore_index=False) # index gives first example\n", - "# with this combination\n", - "df_meta_rawfiles[list(meta_raw_settings)].drop(to_drop, axis=1).drop_duplicates(ignore_index=True)" - ] - }, - { - "cell_type": "markdown", - "id": "031c4e4e-600d-48cb-b025-af851b4d5e26", - "metadata": {}, - "source": [ - "Relatively big samples for different machines of the same kind running with the same firmware:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8cf957f5-d3e6-46c2-b15e-f82cd37e5488", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta_rawfiles.groupby([meta_raw_settings.ms_model, meta_raw_settings.ms_firmware])[\n", - " meta_raw_settings.ms_model].count().sort_values().tail(10)" - ] - }, - { - "cell_type": "markdown", - "id": "b890cf2f-3d6e-4a87-adda-0bf947900971", - "metadata": {}, - "source": [ - "Ignoring instrument software" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0caecd7f-a804-4b11-b761-58f68bbc6a20", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "grouping = df_meta_rawfiles.groupby(list(meta_raw_settings[:3]))\n", - "instrument_counts = grouping[meta_raw_settings.ms_model].count().sort_values()\n", - "msg += (f\" There are a total of {len(instrument_counts)} unique instruments in the entire dataset (based on the instrument name, attributs and serial number)\"\n", - " f\", of which at least {(instrument_counts >= 1000).sum()} have 1,000 raw files assigned to them. Note that the entire dataset contains fractionated measurements.\")\n", - "instrument_counts" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e763c1f0-3ca4-404f-a5f5-28a9acbea6f5", - "metadata": {}, - "outputs": [], - "source": [ - "ms_groups = vaep.pandas.create_dict_of_dicts(grouping.groups, verbose=True, transform_values=list)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "29e8caa4-5a7e-46b6-9758-26661548cf18", - "metadata": {}, - "outputs": [], - "source": [ - "# d = dict()\n", - "# for (k1, k2, k3), v in grouping.groups.items():\n", - "# print(f\"{str((k1,k2,k3)):90}: {len(v):>5}\")\n", - "# if not k1 in d:\n", - "# d[k1] = dict()\n", - "# if not k2 in d[k1]:\n", - "# d[k1][k2] = dict()\n", - "# d[k1][k2][k3] = list(v)\n", - "# assert ms_groups == d" - ] - }, - { - "cell_type": "markdown", - "id": "5719cd88-f9dc-4edb-a5f0-61d27cf67599", - "metadata": {}, - "source": [ - "Save selection yaml" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "163089c0-8889-4421-ba88-00ec28594d3b", - "metadata": {}, - "outputs": [], - "source": [ - "with open(fn_files_per_instrument, 'w') as f:\n", - " yaml.dump(ms_groups, f)" - ] - }, - { - "cell_type": "markdown", - "id": "f09f8a60-bd80-4d3c-b86c-ddd2d25417a2", - "metadata": {}, - "source": [ - "## Quantified files\n", - "\n", - "- export nested files with quantified files based on selection based on identified peptides threshold" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ca9b7ce5-f36c-43ef-8912-95ea9421c5a8", - "metadata": {}, - "outputs": [], - "source": [ - "with open(fn_files_selected) as f:\n", - " files_selected = yaml.safe_load(f)\n", - "print(f'Threshold: {files_selected[\"threshold\"]:,d}')" - ] - }, - { - "cell_type": "markdown", - "id": "c50d4263-d44a-4315-aea2-793473452595", - "metadata": {}, - "source": [ - "- save metadata for selected, quantified samples / raw files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a8ed450f-c9aa-4387-aa97-a33444abd5a9", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta_rawfiles.loc[files_selected['files']].to_csv('data/files_selected_metadata.csv')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e438ba02-93ae-4fb1-9947-d2b741269feb", - "metadata": {}, - "outputs": [], - "source": [ - "grouping = df_meta_rawfiles.loc[files_selected['files']].groupby(list(meta_raw_settings[:3]))\n", - "instrument_counts = grouping[meta_raw_settings.ms_model].count().sort_values()\n", - "N = 500\n", - "msg += (\n", - " f\" Among the {len(files_selected['files'])} raw files with a minimum of {files_selected['threshold']:,d} identified peptides there are a total of {len(instrument_counts)} unique instruments with quantified runs\"\n", - " f\", of which {(instrument_counts >= N).sum()} have at least {N:,d} rawfiles assigned to them.\")\n", - "instrument_counts.to_csv('data/files_selected_per_instrument_counts.csv')\n", - "instrument_counts.to_frame('No. samples')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8c61da71-96a0-45a2-a89f-6ea056948d61", - "metadata": {}, - "outputs": [], - "source": [ - "ms_groups = vaep.pandas.create_dict_of_dicts(grouping.groups, verbose=True, transform_values=list)\n", - "with open(fn_files_per_instrument_selected, 'w') as f:\n", - " yaml.dump(ms_groups, f)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d4d50dcb-0715-4eaf-8d47-ce16385e362e", - "metadata": {}, - "outputs": [], - "source": [ - "print(msg)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.8.13" - }, - "vscode": { - "interpreter": { - "hash": "cf83e9cb890c7f96eb0ae04f39a82254555f56a1a0ed2f03b23a8b40fe6cd31c" - } - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/00_0_hela_metadata_rawfiles.py b/project/00_0_hela_metadata_rawfiles.py deleted file mode 100644 index 2241611e8..000000000 --- a/project/00_0_hela_metadata_rawfiles.py +++ /dev/null @@ -1,219 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: Python 3 -# language: python -# name: python3 -# --- - -# %% [markdown] -# # Rawfile metadata -# -# - generated using `workflows/metadata` -# - all raw files collected ~50,000 - -# %% -from collections import namedtuple -from collections import defaultdict - -import yaml -import numpy as np -import pandas as pd - -import vaep.pandas - -# %% [markdown] -# ## Arguments - -# %% tags=["parameters"] -fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' # Machine parsed metadata from rawfile workflow -# outputs -# All parsed raw files nested by instrument (model, attribute, serial number) -fn_files_per_instrument: str = 'data/files_per_instrument.yaml' -fn_files_selected: str = 'data/samples_selected.yaml' # selected files based on threshold of identified peptides -# Selected parsed raw files nested by instrument (model, attribute, serial number) -fn_files_per_instrument_selected: str = 'data/files_selected_per_instrument.yaml' - -# %% [markdown] -# ### Machine metadata -# -# - read from file using [ThermoRawFileParser](https://github.com/compomics/ThermoRawFileParser) - -# %% -df_meta_rawfiles = pd.read_csv(fn_rawfile_metadata, header=[0, 1], index_col=0, low_memory=False) -date_col = ('FileProperties', 'Content Creation Date') -df_meta_rawfiles[date_col] = pd.to_datetime( - df_meta_rawfiles[date_col]) -df_meta_rawfiles.sort_values(date_col, inplace=True) -df_meta_rawfiles - -# %% -msg = f"A total of {len(df_meta_rawfiles)} raw files could be read using the ThermoFisherRawFileParser." -print(msg) - -# %% -meta_stats = df_meta_rawfiles.describe(include='all') -meta_stats.T - -# %% [markdown] -# subset with variation - -# %% -meta_stats.loc[:, (meta_stats.loc['unique'] > 1) | (meta_stats.loc['std'] > 0.1)].T - -# %% -# needs to go to Config which is not overwriteable by attribute selection -df_meta_rawfiles_columns = df_meta_rawfiles.columns -meta_raw_names = df_meta_rawfiles.columns.droplevel() -assert meta_raw_names.is_unique -df_meta_rawfiles.columns = meta_raw_names -df_meta_rawfiles - -# %% -meta_raw_selected = [ - 'Content Creation Date', - 'Thermo Scientific instrument model', - 'instrument serial number', - 'Software Version', - 'Number of MS1 spectra', - 'Number of MS2 spectra', - 'Number of scans', - 'MS max charge', - 'MS max RT', - 'MS min MZ', - 'MS max MZ', - 'MS scan range', - 'mass resolution', - 'Retention time range', - 'Mz range', - 'beam-type collision-induced dissociation', - 'injection volume setting', - 'dilution factor', -] -df_meta_rawfiles[meta_raw_selected].describe(percentiles=np.linspace(0.05, 0.95, 10)) - -# %% [markdown] -# - `MS min MZ`: outlier clearly shifts means -# - `mass resolution` is unique (can this be?) -# - `dillution factor` is unique (can this be?) - -# %% [markdown] -# ## Instrument type and settings -# -# check some columns describing settings -# - quite some variation due to `MS max charge`: Is it a parameter? - -# %% -MetaRawSettings = namedtuple( - 'MetaRawSettings', - 'ms_model ms_attr ms_sn ms_firmware max_charge mass_res cid_type inject_volume dill_factor') -meta_raw_settings = [ - 'Thermo Scientific instrument model', - 'instrument attribute', - 'instrument serial number', - 'Software Version', - 'MS max charge', - 'mass resolution', - 'beam-type collision-induced dissociation', - 'injection volume setting', - 'dilution factor', -] -meta_raw_settings = MetaRawSettings(*meta_raw_settings) -meta_raw_settings - -# %% -# index gives first example with this combination -# df_meta_rawfiles[list(meta_raw_settings)].drop_duplicates() -df_meta_rawfiles[list(meta_raw_settings)].drop_duplicates(ignore_index=True) - -# %% [markdown] -# view without `MS max charge`: -# - software can be updated -# - variation by `injection volume setting` and instrument over time -# - missing `dilution factor` -# - -# %% -to_drop = ['MS max charge'] -# df_meta_rawfiles[list(meta_raw_settings)].drop(to_drop, -# axis=1).drop_duplicates(ignore_index=False) # index gives first example -# with this combination -df_meta_rawfiles[list(meta_raw_settings)].drop(to_drop, axis=1).drop_duplicates(ignore_index=True) - -# %% [markdown] -# Relatively big samples for different machines of the same kind running with the same firmware: - -# %% -df_meta_rawfiles.groupby([meta_raw_settings.ms_model, meta_raw_settings.ms_firmware])[ - meta_raw_settings.ms_model].count().sort_values().tail(10) - -# %% [markdown] -# Ignoring instrument software - -# %% -grouping = df_meta_rawfiles.groupby(list(meta_raw_settings[:3])) -instrument_counts = grouping[meta_raw_settings.ms_model].count().sort_values() -msg += (f" There are a total of {len(instrument_counts)} unique instruments in the entire dataset (based on the instrument name, attributs and serial number)" - f", of which at least {(instrument_counts >= 1000).sum()} have 1,000 raw files assigned to them. Note that the entire dataset contains fractionated measurements.") -instrument_counts - -# %% -ms_groups = vaep.pandas.create_dict_of_dicts(grouping.groups, verbose=True, transform_values=list) - -# %% -# d = dict() -# for (k1, k2, k3), v in grouping.groups.items(): -# print(f"{str((k1,k2,k3)):90}: {len(v):>5}") -# if not k1 in d: -# d[k1] = dict() -# if not k2 in d[k1]: -# d[k1][k2] = dict() -# d[k1][k2][k3] = list(v) -# assert ms_groups == d - -# %% [markdown] -# Save selection yaml - -# %% -with open(fn_files_per_instrument, 'w') as f: - yaml.dump(ms_groups, f) - -# %% [markdown] -# ## Quantified files -# -# - export nested files with quantified files based on selection based on identified peptides threshold - -# %% -with open(fn_files_selected) as f: - files_selected = yaml.safe_load(f) -print(f'Threshold: {files_selected["threshold"]:,d}') - -# %% [markdown] -# - save metadata for selected, quantified samples / raw files - -# %% -df_meta_rawfiles.loc[files_selected['files']].to_csv('data/files_selected_metadata.csv') - -# %% -grouping = df_meta_rawfiles.loc[files_selected['files']].groupby(list(meta_raw_settings[:3])) -instrument_counts = grouping[meta_raw_settings.ms_model].count().sort_values() -N = 500 -msg += ( - f" Among the {len(files_selected['files'])} raw files with a minimum of {files_selected['threshold']:,d} identified peptides there are a total of {len(instrument_counts)} unique instruments with quantified runs" - f", of which {(instrument_counts >= N).sum()} have at least {N:,d} rawfiles assigned to them.") -instrument_counts.to_csv('data/files_selected_per_instrument_counts.csv') -instrument_counts.to_frame('No. samples') - -# %% -ms_groups = vaep.pandas.create_dict_of_dicts(grouping.groups, verbose=True, transform_values=list) -with open(fn_files_per_instrument_selected, 'w') as f: - yaml.dump(ms_groups, f) - -# %% -print(msg) diff --git a/project/00_1_hela_MQ_summaries.ipynb b/project/00_1_hela_MQ_summaries.ipynb deleted file mode 100644 index 4b563a2ad..000000000 --- a/project/00_1_hela_MQ_summaries.ipynb +++ /dev/null @@ -1,201 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Analysis of `summaries.txt` information\n", - "\n", - "- number of raw files (no here)\n", - "- number of raw files with MQ-Output\n", - "- MS1 per file\n", - "- MS2 per file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import ipywidgets as widgets\n", - "import yaml\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "import vaep\n", - "from vaep.pandas import get_unique_non_unique_columns\n", - "from vaep.pandas import unique_cols\n", - "\n", - "from config import FN_ALL_SUMMARIES\n", - "print(f\"{FN_ALL_SUMMARIES = }\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "lines_to_next_cell": 2, - "tags": [ - "parameters" - ] - }, - "outputs": [], - "source": [ - "FN_ALL_SUMMARIES: str = 'data/mq_summaries.csv' # MqAllSummaries json" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_all_summaries = pd.read_csv(FN_ALL_SUMMARIES, index_col=0)\n", - "mq_all_summaries" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Find unique columns, see [post](https://stackoverflow.com/a/54405767/9684872)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "unique_cols(mq_all_summaries.Multiplicity), unique_cols(\n", - " mq_all_summaries[\"Variable modifications first search\"]) # int, NA" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "columns = get_unique_non_unique_columns(mq_all_summaries)\n", - "mq_all_summaries[columns.unique]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_all_summaries[columns.unique].dtypes" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_all_summaries[columns.unique].iloc[0, :]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Analysis of completeness" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class col_summary:\n", - " MS1 = 'MS'\n", - " MS2 = 'MS/MS'\n", - " MS2_identified = 'MS/MS Identified'\n", - " peptides_identified = 'Peptide Sequences Identified'\n", - "\n", - "\n", - "if mq_all_summaries is None:\n", - " raise ValueError(\"No data assigned\")\n", - "\n", - "MS_spectra = mq_all_summaries[[col_summary.MS1, col_summary.MS2,\n", - " col_summary.MS2_identified, col_summary.peptides_identified]]\n", - "\n", - "\n", - "def compute_summary(threshold_identified):\n", - " mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified\n", - " display(MS_spectra.loc[mask].describe(np.linspace(0.05, 0.95, 10)))\n", - "\n", - "\n", - "w_ions_range = widgets.IntSlider(value=15_000, min=15_000, max=MS_spectra[col_summary.peptides_identified].max())\n", - "display(widgets.interactive(compute_summary, threshold_identified=w_ions_range))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "List of samples without any identified peptides:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = (MS_spectra < 1).any(axis=1)\n", - "MS_spectra.loc[mask]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Export selected list of quantified samples\n", - "\n", - "Based on threshold, save a list of the specified samples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dump_dict = {'threshold': int(w_ions_range.value)}\n", - "mask = MS_spectra[col_summary.peptides_identified] >= w_ions_range.value\n", - "dump_dict['files'] = MS_spectra.loc[mask].index.to_list()\n", - "\n", - "with open('data/samples_selected.yaml', 'w') as f:\n", - " yaml.dump(dump_dict, stream=f)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/00_1_hela_MQ_summaries.py b/project/00_1_hela_MQ_summaries.py deleted file mode 100644 index 2a27a89d4..000000000 --- a/project/00_1_hela_MQ_summaries.py +++ /dev/null @@ -1,106 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: vaep -# language: python -# name: vaep -# --- - -# %% [markdown] -# # Analysis of `summaries.txt` information -# -# - number of raw files (no here) -# - number of raw files with MQ-Output -# - MS1 per file -# - MS2 per file - -# %% -import ipywidgets as widgets -import yaml -import numpy as np -import pandas as pd - -import vaep -from vaep.pandas import get_unique_non_unique_columns -from vaep.pandas import unique_cols - -from config import FN_ALL_SUMMARIES -print(f"{FN_ALL_SUMMARIES = }") - -# %% tags=["parameters"] -FN_ALL_SUMMARIES: str = 'data/mq_summaries.csv' # MqAllSummaries json - - -# %% -mq_all_summaries = pd.read_csv(FN_ALL_SUMMARIES, index_col=0) -mq_all_summaries - -# %% [markdown] -# Find unique columns, see [post](https://stackoverflow.com/a/54405767/9684872) - -# %% -unique_cols(mq_all_summaries.Multiplicity), unique_cols( - mq_all_summaries["Variable modifications first search"]) # int, NA - -# %% -columns = get_unique_non_unique_columns(mq_all_summaries) -mq_all_summaries[columns.unique] - -# %% -mq_all_summaries[columns.unique].dtypes - -# %% -mq_all_summaries[columns.unique].iloc[0, :] - - -# %% [markdown] -# ## Analysis of completeness - -# %% -class col_summary: - MS1 = 'MS' - MS2 = 'MS/MS' - MS2_identified = 'MS/MS Identified' - peptides_identified = 'Peptide Sequences Identified' - - -if mq_all_summaries is None: - raise ValueError("No data assigned") - -MS_spectra = mq_all_summaries[[col_summary.MS1, col_summary.MS2, - col_summary.MS2_identified, col_summary.peptides_identified]] - - -def compute_summary(threshold_identified): - mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified - display(MS_spectra.loc[mask].describe(np.linspace(0.05, 0.95, 10))) - - -w_ions_range = widgets.IntSlider(value=15_000, min=15_000, max=MS_spectra[col_summary.peptides_identified].max()) -display(widgets.interactive(compute_summary, threshold_identified=w_ions_range)) - -# %% [markdown] -# List of samples without any identified peptides: - -# %% -mask = (MS_spectra < 1).any(axis=1) -MS_spectra.loc[mask] - -# %% [markdown] -# ## Export selected list of quantified samples -# -# Based on threshold, save a list of the specified samples - -# %% -dump_dict = {'threshold': int(w_ions_range.value)} -mask = MS_spectra[col_summary.peptides_identified] >= w_ions_range.value -dump_dict['files'] = MS_spectra.loc[mask].index.to_list() - -with open('data/samples_selected.yaml', 'w') as f: - yaml.dump(dump_dict, stream=f) diff --git a/project/00_2_hela_all_raw_files.ipynb b/project/00_2_hela_all_raw_files.ipynb deleted file mode 100644 index 384a5aa09..000000000 --- a/project/00_2_hela_all_raw_files.ipynb +++ /dev/null @@ -1,806 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# RawFiles Database\n", - "\n", - "- overview of raw files, among others\n", - " - filesize\n", - " - duplicates of raw files\n", - " - search for substrings to find special cases (e.g. fractionated samples)\n", - "\n", - "**Outputs**\n", - "\n", - "Created data and figures\n", - "\n", - "```bash\n", - "'data/all_raw_files_dump_duplicated.txt'\n", - "'data/all_raw_files_dump_unique.csv' # csv file\n", - "'Figures/raw_file_overview.pdf'\n", - "```\n", - "\n", - "**Inputs**\n", - "\n", - "```bash\n", - "'data/all_raw_files_dump.txt'\n", - "```\n", - "\n", - "The ladder can be created using `find` on a server:\n", - "\n", - "```bash\n", - "find . -name '*.raw' -exec ls -l {} \\; > all_raw_files_dump_2021_10_27.txt\n", - "# alternative (changes the format)\n", - "find . -name '*.raw' -ls > all_raw_files_dump_2021_10_27.txt\n", - "```\n", - "\n", - "which was executed in the" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from pathlib import Path, PurePosixPath\n", - "from collections import namedtuple\n", - "from functools import partial\n", - "import yaml\n", - "\n", - "import ipywidgets as widgets\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "import logging\n", - "from vaep.logging import setup_logger\n", - "from vaep.analyzers.analyzers import AnalyzePeptides\n", - "from vaep.io.data_objects import MqAllSummaries\n", - "from vaep.io.rawfiles import RawFileViewer, get_unique_stem, find_indices_containing_query, show_fractions\n", - "import config\n", - "from vaep.nb import Config\n", - "from vaep import utils\n", - "\n", - "cfg = Config()\n", - "\n", - "logger = logging.getLogger('vaep')\n", - "logger = setup_logger(logger, fname_base='00_2_hela_all_raw_files_ipynb')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "parameters" - ] - }, - "outputs": [], - "source": [ - "# FN_ALL_RAW_FILES = config.FOLDER_DATA / config.FN_ALL_RAW_FILES\n", - "FN_ALL_RAW_FILES: str = config.FOLDER_DATA / 'all_raw_files_dump_2021_10_29.txt'\n", - "FN_ALL_SUMMARIES: str = config.FN_ALL_SUMMARIES\n", - "FN_PEPTIDE_INTENSITIES = config.FOLDER_DATA / 'df_intensities_N07285_M01000'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "cfg.FN_ALL_RAW_FILES = FN_ALL_RAW_FILES\n", - "cfg.FN_ALL_SUMMARIES = FN_ALL_SUMMARIES\n", - "cfg.FN_PEPTIDE_INTENSITIES = FN_PEPTIDE_INTENSITIES" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "RawFile = namedtuple('RawFile', 'name path bytes')\n", - "\n", - "data = []\n", - "with open(cfg.FN_ALL_RAW_FILES) as f:\n", - " for line in f:\n", - " line = line.split(maxsplit=8) # ignore white spaces in file names, example:\n", - " #'-rw-r--r--. 1 501 501 282917566 Dec 3 2022 ./share_hela_raw/MNT_202220220921_EXLP1_Evo1_LiNi_ - Copy1.raw'\n", - " path = Path(line[-1].strip())\n", - " data.append(RawFile(path.stem, path, int(line[4])))\n", - "\n", - "data = pd.DataFrame.from_records(\n", - " data, columns=RawFile._fields, index=RawFile._fields[0])\n", - "\n", - "data.sort_values(by='path', inplace=True)\n", - "data.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data['size_gb'] = data['bytes'] / 1024 ** 3\n", - "data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fname = 'data/processed/all_raw_file_sizes.csv'\n", - "data.to_csv(fname)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Finding duplicates\n", - "\n", - "- add a numeric index column to identify samples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data['num_index'] = pd.RangeIndex(stop=len(data))\n", - "mask_non_unique = data.reset_index().duplicated(subset=['name', 'bytes'])\n", - "mask_non_unique.index = data.index\n", - "idx_non_unique = data.loc[mask_non_unique].index.unique()\n", - "idx_non_unique # min number of files to remove" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def check_for_duplicates(df):\n", - " if df.index.is_unique:\n", - " print('Only unique files in index.')\n", - " return None\n", - " else:\n", - " non_unique = df.index.value_counts()\n", - " non_unique = non_unique[non_unique > 1]\n", - " # should this be browseable?\n", - " print(f'Number of files with more than 2 duplicates: {(non_unique > 2).sum()}')\n", - " return non_unique\n", - "\n", - "\n", - "non_unique = check_for_duplicates(df=data)\n", - "non_unique" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Are there cases where only two files share the same name and have different file sizes:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data.loc[\n", - " non_unique.index.difference(idx_non_unique)]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For same sized groups, remove first the onces in the `MNT` folder:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_in_MNT_to_remove = None\n", - "non_unique_remaining = None\n", - "if not data.index.is_unique:\n", - " _data_to_remove = data.loc[idx_non_unique]\n", - " data_in_MNT_to_remove = pd.DataFrame()\n", - " non_unique_remaining = pd.DataFrame()\n", - " for idx, g in _data_to_remove.groupby(level=0):\n", - " mask = ['\\\\MNT' in str(x) for x in g.path]\n", - " assert len(mask) != sum(mask), f'All files in MNT subfolders: {idx}'\n", - " data_in_MNT_to_remove = data_in_MNT_to_remove.append(g[mask])\n", - " non_unique_remaining = non_unique_remaining.append(g[[x != True for x in mask]])\n", - "\n", - " del _data_to_remove, mask, idx, g\n", - "\n", - "assert len(data.loc[idx_non_unique]) == len(non_unique_remaining) + len(data_in_MNT_to_remove)\n", - "assert len(non_unique_remaining.loc[['\\\\MNT' in str(x)\n", - " for x in non_unique_remaining.path]]) == 0, \"There are files in MNT folder left\"\n", - "data_in_MNT_to_remove" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The main junk of duplicated files in in `MNT` subfolders" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "non_unique_remaining_counts = check_for_duplicates(non_unique_remaining)\n", - "non_unique_remaining.loc[non_unique_remaining_counts.index.unique()]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Files with the same name and the same size are considered the same." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask_non_unique_remaining = non_unique_remaining.reset_index().duplicated(subset=['name', 'bytes'])\n", - "mask_non_unique_remaining.index = non_unique_remaining.index\n", - "data_to_remove = data_in_MNT_to_remove.append(\n", - " non_unique_remaining.loc[mask_non_unique_remaining]\n", - ")\n", - "data_to_remove" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(f\"Save {data_to_remove['size_gb'].sum():1.0f} GB disk space by deleting {len(data_to_remove)} files.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_unique = data.reset_index().set_index('num_index').drop(\n", - " data_to_remove.set_index('num_index').index).set_index('name')\n", - "data_unique" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Make sure that every index to remove is still present in `data_unique` which is data to keep" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_unique.loc[data_to_remove.index.unique()]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "assert len(data_unique) + len(data_to_remove) == len(data)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Show files which are duplicated, but have different sizes:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# two files have the same name, but different sizes\n", - "data_unique.loc[data_unique.index.duplicated(False)] if not data_unique.index.is_unique else None" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Save unique files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "cfg.FN_ALL_RAW_FILES_UNIQUE = utils.append_to_filepath(\n", - " cfg.FN_ALL_RAW_FILES, config.build_df_fname(\n", - " data_unique, 'unique'), new_suffix='csv')\n", - "data_unique.to_csv(cfg.FN_ALL_RAW_FILES_UNIQUE)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Export file paths to file to remove them, e.g using `rm $( all_raw_files_dump_duplicated_cleaned.txt\n", - "ls `cat all_raw_files_dump_duplicated_cleaned`\n", - "rm -i `cat all_raw_files_dump_duplicated_cleaned`\n", - "rm -i $( They can be duplicated files with the same file size. Not the case for now" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "idx_shared = mq_summaries.df.index.intersection(data_unique.index)\n", - "\n", - "_file_sizes = data_unique.loc[idx_shared, 'size_gb']\n", - "_file_sizes.loc[_file_sizes.index.duplicated(False)]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_file_sizes = _file_sizes.loc[~_file_sizes.index.duplicated(keep='last')]\n", - "mq_summaries.df.loc[idx_shared, 'file size in GB'] = _file_sizes\n", - "cols = ['Peptide Sequences Identified', 'file size in GB']\n", - "mq_summaries.df[cols]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_summaries.df[cols].describe(np.linspace(0.05, 0.95, 10))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fig, axes = plt.subplots(ncols=3, gridspec_kw={\"width_ratios\": [\n", - " 5, 1, 1], \"wspace\": 0.3}, figsize=(20, 8))\n", - "\n", - "ax = axes[0]\n", - "ax = mq_summaries.df.plot.scatter(x=cols[0], y=cols[1], ax=ax)\n", - "ax.axvline(x=15000)\n", - "\n", - "ax = axes[1]\n", - "ax = mq_summaries.df[cols[0]].plot(kind='box', ax=ax)\n", - "\n", - "\n", - "ax = axes[2]\n", - "ax = mq_summaries.df[cols[1]].plot(kind='box', ax=ax)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For some files with a large number of identified peptides, the file size information seems to be missing." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "cfg.figure_1 = config.FIGUREFOLDER / 'figure_1.pdf'\n", - "\n", - "fig.savefig(cfg.figure_1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "threshold = 15_000\n", - "mask = mq_summaries.df[cols[0]] > threshold\n", - "print(\n", - " f\"for threshold of {threshold:,d} quantified peptides:\\n\"\n", - " f\"Total number of files is {mask.sum()}\\n\"\n", - " \"Minimum file-size is {:.3f} GB.\\n\".format(\n", - " mq_summaries.df.loc[mask, cols[1]].min())\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Meta data for all samples" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### From raw file reading" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "files_to_parse = data_unique.loc[idx_shared, 'path'].apply(lambda path: str(PurePosixPath(path)).strip())\n", - "files_to_parse = dict(files=files_to_parse.to_list())\n", - "cfg.remote_files = config.FOLDER_DATA / 'remote_files.yaml'\n", - "with open(cfg.remote_files, 'w') as f:\n", - " yaml.dump(files_to_parse, f)\n", - "print(f\"Saved list of files to: {cfg.remote_files}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### From file name" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "analysis = AnalyzePeptides.from_csv(cfg.FN_ALL_RAW_FILES_UNIQUE, index_col='name') # ToDo: Add numbers to file names\n", - "analysis.df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "analysis.add_metadata(add_prop_not_na=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "Metadata has fewer cases due to duplicates with differnt file sizes ( see above)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "analysis.df.loc[analysis.df.index.duplicated(False)] # keep the larger one" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## cfg" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "vars(cfg) # return a dict which is rendered differently in ipython" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.8.13" - }, - "vscode": { - "interpreter": { - "hash": "cf83e9cb890c7f96eb0ae04f39a82254555f56a1a0ed2f03b23a8b40fe6cd31c" - } - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/00_2_hela_all_raw_files.py b/project/00_2_hela_all_raw_files.py deleted file mode 100644 index 06949d392..000000000 --- a/project/00_2_hela_all_raw_files.py +++ /dev/null @@ -1,432 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: Python 3 -# language: python -# name: python3 -# --- - -# %% [markdown] -# # RawFiles Database -# -# - overview of raw files, among others -# - filesize -# - duplicates of raw files -# - search for substrings to find special cases (e.g. fractionated samples) -# -# **Outputs** -# -# Created data and figures -# -# ```bash -# 'data/all_raw_files_dump_duplicated.txt' -# 'data/all_raw_files_dump_unique.csv' # csv file -# 'Figures/raw_file_overview.pdf' -# ``` -# -# **Inputs** -# -# ```bash -# 'data/all_raw_files_dump.txt' -# ``` -# -# The ladder can be created using `find` on a server: -# -# ```bash -# find . -name '*.raw' -exec ls -l {} \; > all_raw_files_dump_2021_10_27.txt -# # alternative (changes the format) -# find . -name '*.raw' -ls > all_raw_files_dump_2021_10_27.txt -# ``` -# -# which was executed in the - -# %% -from pathlib import Path, PurePosixPath -from collections import namedtuple -from functools import partial -import yaml - -import ipywidgets as widgets -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd - -import logging -from vaep.logging import setup_logger -from vaep.analyzers.analyzers import AnalyzePeptides -from vaep.io.data_objects import MqAllSummaries -from vaep.io.rawfiles import RawFileViewer, get_unique_stem, find_indices_containing_query, show_fractions -import config -from vaep.nb import Config -from vaep import utils - -cfg = Config() - -logger = logging.getLogger('vaep') -logger = setup_logger(logger, fname_base='00_2_hela_all_raw_files_ipynb') - -# %% tags=["parameters"] -# FN_ALL_RAW_FILES = config.FOLDER_DATA / config.FN_ALL_RAW_FILES -FN_ALL_RAW_FILES: str = config.FOLDER_DATA / 'all_raw_files_dump_2021_10_29.txt' -FN_ALL_SUMMARIES: str = config.FN_ALL_SUMMARIES -FN_PEPTIDE_INTENSITIES = config.FOLDER_DATA / 'df_intensities_N07285_M01000' - -# %% -cfg.FN_ALL_RAW_FILES = FN_ALL_RAW_FILES -cfg.FN_ALL_SUMMARIES = FN_ALL_SUMMARIES -cfg.FN_PEPTIDE_INTENSITIES = FN_PEPTIDE_INTENSITIES - -# %% -RawFile = namedtuple('RawFile', 'name path bytes') - -data = [] -with open(cfg.FN_ALL_RAW_FILES) as f: - for line in f: - line = line.split(maxsplit=8) # ignore white spaces in file names, example: - #'-rw-r--r--. 1 501 501 282917566 Dec 3 2022 ./share_hela_raw/MNT_202220220921_EXLP1_Evo1_LiNi_ - Copy1.raw' - path = Path(line[-1].strip()) - data.append(RawFile(path.stem, path, int(line[4]))) - -data = pd.DataFrame.from_records( - data, columns=RawFile._fields, index=RawFile._fields[0]) - -data.sort_values(by='path', inplace=True) -data.head() - -# %% -data['size_gb'] = data['bytes'] / 1024 ** 3 -data - -# %% -fname = 'data/processed/all_raw_file_sizes.csv' -data.to_csv(fname) - -# %% [markdown] -# ## Finding duplicates -# -# - add a numeric index column to identify samples - -# %% -data['num_index'] = pd.RangeIndex(stop=len(data)) -mask_non_unique = data.reset_index().duplicated(subset=['name', 'bytes']) -mask_non_unique.index = data.index -idx_non_unique = data.loc[mask_non_unique].index.unique() -idx_non_unique # min number of files to remove - - -# %% -def check_for_duplicates(df): - if df.index.is_unique: - print('Only unique files in index.') - return None - else: - non_unique = df.index.value_counts() - non_unique = non_unique[non_unique > 1] - # should this be browseable? - print(f'Number of files with more than 2 duplicates: {(non_unique > 2).sum()}') - return non_unique - - -non_unique = check_for_duplicates(df=data) -non_unique - -# %% [markdown] -# Are there cases where only two files share the same name and have different file sizes: - -# %% -data.loc[ - non_unique.index.difference(idx_non_unique)] - -# %% [markdown] -# For same sized groups, remove first the onces in the `MNT` folder: - -# %% -data_in_MNT_to_remove = None -non_unique_remaining = None -if not data.index.is_unique: - _data_to_remove = data.loc[idx_non_unique] - data_in_MNT_to_remove = pd.DataFrame() - non_unique_remaining = pd.DataFrame() - for idx, g in _data_to_remove.groupby(level=0): - mask = ['\\MNT' in str(x) for x in g.path] - assert len(mask) != sum(mask), f'All files in MNT subfolders: {idx}' - data_in_MNT_to_remove = data_in_MNT_to_remove.append(g[mask]) - non_unique_remaining = non_unique_remaining.append(g[[x != True for x in mask]]) - - del _data_to_remove, mask, idx, g - -assert len(data.loc[idx_non_unique]) == len(non_unique_remaining) + len(data_in_MNT_to_remove) -assert len(non_unique_remaining.loc[['\\MNT' in str(x) - for x in non_unique_remaining.path]]) == 0, "There are files in MNT folder left" -data_in_MNT_to_remove - -# %% [markdown] -# The main junk of duplicated files in in `MNT` subfolders - -# %% -non_unique_remaining_counts = check_for_duplicates(non_unique_remaining) -non_unique_remaining.loc[non_unique_remaining_counts.index.unique()] - -# %% [markdown] -# Files with the same name and the same size are considered the same. - -# %% -mask_non_unique_remaining = non_unique_remaining.reset_index().duplicated(subset=['name', 'bytes']) -mask_non_unique_remaining.index = non_unique_remaining.index -data_to_remove = data_in_MNT_to_remove.append( - non_unique_remaining.loc[mask_non_unique_remaining] -) -data_to_remove - -# %% -print(f"Save {data_to_remove['size_gb'].sum():1.0f} GB disk space by deleting {len(data_to_remove)} files.") - -# %% -data_unique = data.reset_index().set_index('num_index').drop( - data_to_remove.set_index('num_index').index).set_index('name') -data_unique - -# %% [markdown] -# Make sure that every index to remove is still present in `data_unique` which is data to keep - -# %% -data_unique.loc[data_to_remove.index.unique()] - -# %% -assert len(data_unique) + len(data_to_remove) == len(data) - -# %% [markdown] -# Show files which are duplicated, but have different sizes: - -# %% -# two files have the same name, but different sizes -data_unique.loc[data_unique.index.duplicated(False)] if not data_unique.index.is_unique else None - -# %% [markdown] -# Save unique files - -# %% -cfg.FN_ALL_RAW_FILES_UNIQUE = utils.append_to_filepath( - cfg.FN_ALL_RAW_FILES, config.build_df_fname( - data_unique, 'unique'), new_suffix='csv') -data_unique.to_csv(cfg.FN_ALL_RAW_FILES_UNIQUE) - -# %% [markdown] -# Export file paths to file to remove them, e.g using `rm $( all_raw_files_dump_duplicated_cleaned.txt -# ls `cat all_raw_files_dump_duplicated_cleaned` -# rm -i `cat all_raw_files_dump_duplicated_cleaned` -# rm -i $( They can be duplicated files with the same file size. Not the case for now - -# %% -idx_shared = mq_summaries.df.index.intersection(data_unique.index) - -_file_sizes = data_unique.loc[idx_shared, 'size_gb'] -_file_sizes.loc[_file_sizes.index.duplicated(False)] - -# %% -_file_sizes = _file_sizes.loc[~_file_sizes.index.duplicated(keep='last')] -mq_summaries.df.loc[idx_shared, 'file size in GB'] = _file_sizes -cols = ['Peptide Sequences Identified', 'file size in GB'] -mq_summaries.df[cols] - -# %% -mq_summaries.df[cols].describe(np.linspace(0.05, 0.95, 10)) - -# %% -fig, axes = plt.subplots(ncols=3, gridspec_kw={"width_ratios": [ - 5, 1, 1], "wspace": 0.3}, figsize=(20, 8)) - -ax = axes[0] -ax = mq_summaries.df.plot.scatter(x=cols[0], y=cols[1], ax=ax) -ax.axvline(x=15000) - -ax = axes[1] -ax = mq_summaries.df[cols[0]].plot(kind='box', ax=ax) - - -ax = axes[2] -ax = mq_summaries.df[cols[1]].plot(kind='box', ax=ax) - -# %% [markdown] -# For some files with a large number of identified peptides, the file size information seems to be missing. - -# %% -cfg.figure_1 = config.FIGUREFOLDER / 'figure_1.pdf' - -fig.savefig(cfg.figure_1) - -# %% -threshold = 15_000 -mask = mq_summaries.df[cols[0]] > threshold -print( - f"for threshold of {threshold:,d} quantified peptides:\n" - f"Total number of files is {mask.sum()}\n" - "Minimum file-size is {:.3f} GB.\n".format( - mq_summaries.df.loc[mask, cols[1]].min()) -) - -# %% [markdown] -# ## Meta data for all samples - -# %% [markdown] -# ### From raw file reading - -# %% -files_to_parse = data_unique.loc[idx_shared, 'path'].apply(lambda path: str(PurePosixPath(path)).strip()) -files_to_parse = dict(files=files_to_parse.to_list()) -cfg.remote_files = config.FOLDER_DATA / 'remote_files.yaml' -with open(cfg.remote_files, 'w') as f: - yaml.dump(files_to_parse, f) -print(f"Saved list of files to: {cfg.remote_files}") - -# %% [markdown] -# ### From file name - -# %% -analysis = AnalyzePeptides.from_csv(cfg.FN_ALL_RAW_FILES_UNIQUE, index_col='name') # ToDo: Add numbers to file names -analysis.df - -# %% -analysis.add_metadata(add_prop_not_na=False) - -# %% [markdown] -# Metadata has fewer cases due to duplicates with differnt file sizes ( see above) - -# %% -analysis.df.loc[analysis.df.index.duplicated(False)] # keep the larger one - -# %% [markdown] -# ## cfg - -# %% -vars(cfg) # return a dict which is rendered differently in ipython - -# %% diff --git a/project/00_3_0_pride_metadata_creation.ipynb b/project/00_3_0_pride_metadata_creation.ipynb deleted file mode 100644 index a074c91f5..000000000 --- a/project/00_3_0_pride_metadata_creation.ipynb +++ /dev/null @@ -1,361 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "823351d5", - "metadata": {}, - "source": [ - "# Selected files\n", - "\n", - "- document metadata and file sizes of published dataset in Scientific Data Report\n", - "\n", - "## Contents\n", - "\n", - "1. Number of files per instrument\n", - "2. Rawfile sizes per instrument\n", - "3. peptide - rawfile map (protein group, precursor)?\n", - " - based on selected samples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "123e3468", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "from pathlib import Path\n", - "import pandas as pd" - ] - }, - { - "cell_type": "markdown", - "id": "6f7c2327", - "metadata": {}, - "source": [ - "## PARAMETERS" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7e148b4a", - "metadata": {}, - "outputs": [], - "source": [ - "fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id\n", - "fn_raw_file_size: str = 'processed/all_raw_file_sizes.csv' # raw file sizes\n", - "fn_rawfile_metadata: str = 'data/rawfile_metadata.csv'\n", - "fn_summaries: str = 'data/processed/all_summaries.json'\n", - "date_col: str = 'Content Creation Date'\n", - "out_folder: str = 'data/dev_datasets/pride_upload'" - ] - }, - { - "cell_type": "markdown", - "id": "5ff07632", - "metadata": {}, - "source": [ - "## Prepare outputs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "14eedb3e", - "metadata": {}, - "outputs": [], - "source": [ - "out_folder = Path(out_folder)\n", - "out_folder.mkdir(exist_ok=True)\n", - "files_out = dict()" - ] - }, - { - "cell_type": "markdown", - "id": "9d43c889", - "metadata": {}, - "source": [ - "## ID mapping\n", - "\n", - "- artefact of local vs pride data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "12762362", - "metadata": {}, - "outputs": [], - "source": [ - "df_ids = pd.read_csv(fn_id_old_new, index_col=0)\n", - "df_ids" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d7b493f5", - "metadata": {}, - "outputs": [], - "source": [ - "df_ids.index.is_unique" - ] - }, - { - "cell_type": "markdown", - "id": "9defcf5a", - "metadata": {}, - "source": [ - "## Raw file sizes" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fe25de60", - "metadata": {}, - "outputs": [], - "source": [ - "df_raw_file_size = pd.read_csv(fn_raw_file_size, index_col=0)\n", - "df_raw_file_size" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c08a9411", - "metadata": {}, - "outputs": [], - "source": [ - "df_raw_file_size.index.is_unique" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "36527734", - "metadata": {}, - "outputs": [], - "source": [ - "df_raw_file_size['path'] = df_raw_file_size['path'].apply(lambda x: Path(x).as_posix())\n", - "df_raw_file_size = df_raw_file_size.reset_index().set_index('path')\n", - "df_raw_file_size" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a8b484c0", - "metadata": {}, - "outputs": [], - "source": [ - "df_raw_file_size = df_raw_file_size.loc[df_ids['Path_old'].str[2:].to_list()]\n", - "df_raw_file_size" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6f0ac8b4", - "metadata": {}, - "outputs": [], - "source": [ - "df_raw_file_size = df_raw_file_size.reset_index().set_index('name')" - ] - }, - { - "cell_type": "markdown", - "id": "6d63ff8a", - "metadata": {}, - "source": [ - "## Raw file metadata extracted from ThermoRawFileParser" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1fab8bf8", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta = pd.read_csv(fn_rawfile_metadata, header=[0, 1], index_col=0, low_memory=False)\n", - "assert df_meta.index.is_unique\n", - "df_meta" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "476ecb97", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta = df_meta.loc[df_ids.index]\n", - "df_meta.columns = df_meta.columns.droplevel() # remove top level name\n", - "df_meta" - ] - }, - { - "cell_type": "markdown", - "id": "a97c9046", - "metadata": {}, - "source": [ - "## Summary files from MaxQuant search" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "11a6f39c", - "metadata": {}, - "outputs": [], - "source": [ - "df_summaries = pd.read_json(fn_summaries, orient='index')\n", - "assert df_summaries.index.is_unique\n", - "df_summaries = df_summaries.loc[df_meta.index]\n", - "df_summaries" - ] - }, - { - "cell_type": "markdown", - "id": "934fca92", - "metadata": {}, - "source": [ - "# Combine data and dump" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "63e0cf03", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta = (df_ids\n", - " .join(df_raw_file_size)\n", - " .join(df_meta)\n", - " .join(df_summaries)\n", - " )\n", - "df_meta" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "febfc785", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta = df_meta.set_index('new_sample_id')\n", - "df_meta.index.name = 'Sample ID'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ee5caddf", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta = (df_meta\n", - " .drop(['Path_old', 'Pathname', 'path'], axis=1)\n", - " .rename({'Path_new': 'Pathname'}, axis=1)\n", - " .dropna(how='all', axis=1)\n", - " .convert_dtypes()\n", - " .assign(**{date_col: lambda df_meta: pd.to_datetime(df_meta[date_col])})\n", - " )\n", - "df_meta" - ] - }, - { - "cell_type": "markdown", - "id": "99fc9713", - "metadata": {}, - "source": [ - "Save curated data for dumped files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "717eb728", - "metadata": {}, - "outputs": [], - "source": [ - "fname = out_folder / 'pride_metadata.csv'\n", - "files_out[fname.name] = fname.as_posix()\n", - "df_meta.to_csv(fname)\n", - "\n", - "fname = out_folder / 'pride_metadata_schema.json'\n", - "files_out[fname.name] = fname.as_posix()\n", - "df_meta.dtypes.astype('string').to_json(fname)" - ] - }, - { - "cell_type": "markdown", - "id": "a68385fe", - "metadata": {}, - "source": [ - "# Analysis" - ] - }, - { - "cell_type": "markdown", - "id": "01760dca", - "metadata": {}, - "source": [ - "How to load dumped file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9a7c801e", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "dtypes = pd.read_json(\n", - " files_out['pride_metadata_schema.json'],\n", - " orient='index'\n", - ").squeeze()\n", - "mask_dates = dtypes.str.contains('datetime') # date columns need to be provide separately\n", - "pd.read_csv(files_out['pride_metadata.csv'],\n", - " parse_dates=mask_dates.loc[mask_dates].index.to_list(),\n", - " dtype=dtypes.loc[~mask_dates].to_dict()\n", - " ).dtypes" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "566cf8b6", - "metadata": {}, - "outputs": [], - "source": [ - "files_out" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "67d001a5", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/00_3_0_pride_metadata_creation.py b/project/00_3_0_pride_metadata_creation.py deleted file mode 100644 index 9165f16b2..000000000 --- a/project/00_3_0_pride_metadata_creation.py +++ /dev/null @@ -1,165 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: Python 3 -# language: python -# name: python3 -# --- - -# %% [markdown] -# # Selected files -# -# - document metadata and file sizes of published dataset in Scientific Data Report -# -# ## Contents -# -# 1. Number of files per instrument -# 2. Rawfile sizes per instrument -# 3. peptide - rawfile map (protein group, precursor)? -# - based on selected samples - -# %% -from pathlib import Path -import pandas as pd - - -# %% [markdown] -# ## PARAMETERS - -# %% -fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id -fn_raw_file_size: str = 'processed/all_raw_file_sizes.csv' # raw file sizes -fn_rawfile_metadata: str = 'data/rawfile_metadata.csv' -fn_summaries: str = 'data/processed/all_summaries.json' -date_col: str = 'Content Creation Date' -out_folder: str = 'data/dev_datasets/pride_upload' - -# %% [markdown] -# ## Prepare outputs - -# %% -out_folder = Path(out_folder) -out_folder.mkdir(exist_ok=True) -files_out = dict() - -# %% [markdown] -# ## ID mapping -# -# - artefact of local vs pride data - -# %% -df_ids = pd.read_csv(fn_id_old_new, index_col=0) -df_ids - -# %% -df_ids.index.is_unique - -# %% [markdown] -# ## Raw file sizes - -# %% -df_raw_file_size = pd.read_csv(fn_raw_file_size, index_col=0) -df_raw_file_size - -# %% -df_raw_file_size.index.is_unique - -# %% -df_raw_file_size['path'] = df_raw_file_size['path'].apply(lambda x: Path(x).as_posix()) -df_raw_file_size = df_raw_file_size.reset_index().set_index('path') -df_raw_file_size - -# %% -df_raw_file_size = df_raw_file_size.loc[df_ids['Path_old'].str[2:].to_list()] -df_raw_file_size - -# %% -df_raw_file_size = df_raw_file_size.reset_index().set_index('name') - -# %% [markdown] -# ## Raw file metadata extracted from ThermoRawFileParser - -# %% -df_meta = pd.read_csv(fn_rawfile_metadata, header=[0, 1], index_col=0, low_memory=False) -assert df_meta.index.is_unique -df_meta - -# %% -df_meta = df_meta.loc[df_ids.index] -df_meta.columns = df_meta.columns.droplevel() # remove top level name -df_meta - -# %% [markdown] -# ## Summary files from MaxQuant search - -# %% -df_summaries = pd.read_json(fn_summaries, orient='index') -assert df_summaries.index.is_unique -df_summaries = df_summaries.loc[df_meta.index] -df_summaries - -# %% [markdown] -# # Combine data and dump - -# %% -df_meta = (df_ids - .join(df_raw_file_size) - .join(df_meta) - .join(df_summaries) - ) -df_meta - -# %% -df_meta = df_meta.set_index('new_sample_id') -df_meta.index.name = 'Sample ID' - -# %% -df_meta = (df_meta - .drop(['Path_old', 'Pathname', 'path'], axis=1) - .rename({'Path_new': 'Pathname'}, axis=1) - .dropna(how='all', axis=1) - .convert_dtypes() - .assign(**{date_col: lambda df_meta: pd.to_datetime(df_meta[date_col])}) - ) -df_meta - -# %% [markdown] -# Save curated data for dumped files - -# %% -fname = out_folder / 'pride_metadata.csv' -files_out[fname.name] = fname.as_posix() -df_meta.to_csv(fname) - -fname = out_folder / 'pride_metadata_schema.json' -files_out[fname.name] = fname.as_posix() -df_meta.dtypes.astype('string').to_json(fname) - -# %% [markdown] -# # Analysis - -# %% [markdown] -# How to load dumped file - -# %% -dtypes = pd.read_json( - files_out['pride_metadata_schema.json'], - orient='index' -).squeeze() -mask_dates = dtypes.str.contains('datetime') # date columns need to be provide separately -pd.read_csv(files_out['pride_metadata.csv'], - parse_dates=mask_dates.loc[mask_dates].index.to_list(), - dtype=dtypes.loc[~mask_dates].to_dict() - ).dtypes - - -# %% -files_out - -# %% diff --git a/project/00_3_1_pride_metadata_analysis.ipynb b/project/00_3_1_pride_metadata_analysis.ipynb deleted file mode 100644 index 54452b7d9..000000000 --- a/project/00_3_1_pride_metadata_analysis.ipynb +++ /dev/null @@ -1,530 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "d9988d7d", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "id": "58232092", - "metadata": {}, - "source": [ - "## Output Excel for Analysis" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fba8c071", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "from pathlib import Path\n", - "import matplotlib.pyplot as plt\n", - "import pandas as pd\n", - "import seaborn\n", - "\n", - "\n", - "from vaep.io import thermo_raw_files\n", - "import vaep.pandas\n", - "\n", - "plt.rcParams['figure.figsize'] = [4, 3]\n", - "vaep.plotting.make_large_descriptors(5)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "af37ae56", - "metadata": { - "incorrectly_encoded_metadata": "[tags=[\"parameters\"]]" - }, - "outputs": [], - "source": [ - "fn_meta = 'data/pride_metadata.csv'\n", - "date_col: str = 'Content Creation Date'\n", - "out_folder: str = 'data/dev_datasets/pride_upload'" - ] - }, - { - "cell_type": "markdown", - "id": "e2dc3abc", - "metadata": {}, - "source": [ - "## Prepare outputs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "53d6f5dd", - "metadata": {}, - "outputs": [], - "source": [ - "out_folder = Path(out_folder)\n", - "out_folder.mkdir(exist_ok=True)\n", - "files_out = dict()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dc84eb5d", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta = pd.read_csv(fn_meta, index_col=0)\n", - "df_meta" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ce35f226", - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "df_meta['instrument_label'] = (\n", - " df_meta[\"Thermo Scientific instrument model\"].str.replace(' ', '-')\n", - " + '_'\n", - " + df_meta[\"instrument serial number\"].str.split('#').str[-1]\n", - ")\n", - "\n", - "# {k: k.replace('-Orbitrap_', ' ').replace('-', ' ').replace('_', ' ')\n", - "# for k in df_meta['instrument_label'].unique()}\n", - "# further small changes applied manually\n", - "# based on https://www.ebi.ac.uk/ols4/\n", - "#\n", - "# Q Exactive HF-X MS:1002877\n", - "# Q Exactive HF MS:1002523\n", - "# Orbitrap Exploris 480 MS:1003028\n", - "# Exactive Plus MS:1002526\n", - "# Q Exactive MS:1001911\n", - "# Orbitrap Fusion Lumos MS:1002732\n", - "\n", - "instrument_labels = {'Q-Exactive-Orbitrap_1': 'Q Exactive 1',\n", - " 'Q-Exactive-Plus-Orbitrap_1': 'Exactive Plus 1',\n", - " 'Q-Exactive-HF-Orbitrap_206': 'Q Exactive HF 206',\n", - " 'Q-Exactive-Plus-Orbitrap_143': 'Exactive Plus 143',\n", - " 'Q-Exactive-HF-Orbitrap_1': 'Q Exactive HF 1',\n", - " 'Q-Exactive-HF-Orbitrap_147': 'Q Exactive HF 147',\n", - " 'Q-Exactive-HF-Orbitrap_204': 'Q Exactive HF 204',\n", - " 'Q-Exactive-HF-Orbitrap_148': 'Q Exactive HF 148',\n", - " 'Q-Exactive-HF-Orbitrap_207': 'Q Exactive HF 207',\n", - " 'Q-Exactive-HF-Orbitrap_143': 'Q Exactive HF 143',\n", - " 'Orbitrap-Fusion-Lumos_FSN20115': 'Orbitrap Fusion Lumos FSN20115',\n", - " 'Q-Exactive-HF-Orbitrap_2612': 'Q Exactive HF 2612',\n", - " 'Q-Exactive-HF-X-Orbitrap_6016': 'Q Exactive HF-X 6016',\n", - " 'Q-Exactive-HF-X-Orbitrap_6004': 'Q Exactive HF-X 6004',\n", - " 'Q-Exactive-HF-X-Orbitrap_6075': 'Q Exactive HF-X 6075',\n", - " 'Q-Exactive-HF-X-Orbitrap_6078': 'Q Exactive HF-X 6078',\n", - " 'Q-Exactive-HF-X-Orbitrap_6070': 'Q Exactive HF-X 6070',\n", - " 'Q-Exactive-HF-X-Orbitrap_6071': 'Q Exactive HF-X 6071',\n", - " 'Q-Exactive-HF-X-Orbitrap_6011': 'Q Exactive HF-X 6011',\n", - " 'Q-Exactive-HF-X-Orbitrap_6073': 'Q Exactive HF-X 6073',\n", - " 'Q-Exactive-HF-X-Orbitrap_6101': 'Q Exactive HF-X 6101',\n", - " 'Q-Exactive-HF-X-Orbitrap_6096': 'Q Exactive HF-X 6096',\n", - " 'Exactive-Series-Orbitrap_6004': 'Exactive Series 6004',\n", - " 'Q-Exactive-HF-X-Orbitrap_6043': 'Q Exactive HF-X 6043',\n", - " 'Q-Exactive-HF-X-Orbitrap_6025': 'Q Exactive HF-X 6025',\n", - " 'Q-Exactive-HF-X-Orbitrap_6022': 'Q Exactive HF-X 6022',\n", - " 'Q-Exactive-HF-X-Orbitrap_6023': 'Q Exactive HF-X 6023',\n", - " 'Q-Exactive-HF-X-Orbitrap_6028': 'Q Exactive HF-X 6028',\n", - " 'Q-Exactive-HF-X-Orbitrap_6013': 'Q Exactive HF-X 6013',\n", - " 'Q-Exactive-HF-X-Orbitrap_6044': 'Q Exactive HF-X 6044',\n", - " 'Q-Exactive-HF-X-Orbitrap_6324': 'Q Exactive HF-X 6324',\n", - " 'Orbitrap-Exploris-480_Invalid_SN_0001': 'Orbitrap Exploris 480 Invalid SN 0001',\n", - " 'Orbitrap-Exploris-480_MA10134C': 'Orbitrap Exploris 480 MA10134C',\n", - " 'Orbitrap-Exploris-480_MA10132C': 'Orbitrap Exploris 480 MA10132C',\n", - " 'Orbitrap-Exploris-480_MA10130C': 'Orbitrap Exploris 480 MA10130C',\n", - " 'Orbitrap-Exploris-480_MA10215C': 'Orbitrap Exploris 480 MA10215C'}\n", - "\n", - "df_meta[\"instrument_label\"] = df_meta[\"instrument_label\"].replace(instrument_labels)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5a6e9cd8", - "metadata": {}, - "outputs": [], - "source": [ - "writer_args = dict(float_format='%.3f')\n", - "fname = out_folder / 'pride_data_infos.xlsx'\n", - "files_out[fname.name] = fname.as_posix()\n", - "excel_writer = pd.ExcelWriter(fname)" - ] - }, - { - "cell_type": "markdown", - "id": "afcf4bf8", - "metadata": {}, - "source": [ - "## Varying data between runs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "17db54de", - "metadata": {}, - "outputs": [], - "source": [ - "meta_stats = df_meta.describe(include='all')\n", - "meta_stats.T.to_excel(excel_writer, sheet_name='des_stats', **writer_args)\n", - "\n", - "view = meta_stats.loc[:, (meta_stats.loc['unique'] > 1)\n", - " | (meta_stats.loc['std'] > 0.01)].T\n", - "view.to_excel(excel_writer, sheet_name='des_stats_varying', **writer_args)" - ] - }, - { - "cell_type": "markdown", - "id": "fec4afa2", - "metadata": {}, - "source": [ - "## Instruments in selection" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "efce5cbd", - "metadata": {}, - "outputs": [], - "source": [ - "thermo_raw_files.cols_instrument" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "577be1d5", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta[date_col] = pd.to_datetime(df_meta[date_col])\n", - "\n", - "counts_instrument = (df_meta\n", - " .groupby(thermo_raw_files.cols_instrument)[date_col]\n", - " .agg(['count', 'min', 'max'])\n", - " .sort_values(by=thermo_raw_files.cols_instrument[:2] + ['count'], ascending=False))\n", - "\n", - "counts_instrument = counts_instrument.join(\n", - " (df_meta\n", - " [[*thermo_raw_files.cols_instrument, 'instrument_label']]\n", - " .drop_duplicates()\n", - " .set_index(thermo_raw_files.cols_instrument)\n", - " )\n", - " .set_index('instrument_label', append=True)\n", - ")\n", - "counts_instrument.to_excel(\n", - " excel_writer, sheet_name='instruments', **writer_args)\n", - "counts_instrument" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "087c2c08", - "metadata": {}, - "outputs": [], - "source": [ - "top10_instruments = counts_instrument['count'].nlargest(10)\n", - "top10_instruments" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7aceab19", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "mask_top10_instruments = (df_meta[thermo_raw_files.cols_instrument]\n", - " .apply(\n", - " lambda x: tuple(x) in top10_instruments.index, axis=1))\n", - "assert mask_top10_instruments.sum() == top10_instruments.sum()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "74377ab0", - "metadata": {}, - "outputs": [], - "source": [ - "# counts_instrument = (df_meta\n", - "# .groupby(['instrument_label'])[date_col]\n", - "# .agg(['count', 'min', 'max'])\n", - "# .sort_values('count', ascending=False)\n", - "# )\n", - "counts_instrument = (counts_instrument\n", - " .reset_index()\n", - " .set_index('instrument_label')\n", - " ['count']\n", - " .sort_values(ascending=False)\n", - " )\n", - "counts_instrument" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2d48b585", - "metadata": {}, - "outputs": [], - "source": [ - "fig, ax = plt.subplots()\n", - "ax = (counts_instrument\n", - " .plot\n", - " .bar(\n", - " ax=ax,\n", - " )\n", - " )\n", - "ax.set_xlabel('')\n", - "ax.set_ylabel('number of samples (runs)')\n", - "fname = out_folder / 'number_of_samples_per_instrument.pdf'\n", - "files_out[fname.name] = fname.as_posix()\n", - "vaep.savefig(fig, fname)" - ] - }, - { - "cell_type": "markdown", - "id": "f44798a4", - "metadata": {}, - "source": [ - "## File size and number of identifications" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "254018bd", - "metadata": {}, - "outputs": [], - "source": [ - "cols = ['Peptide Sequences Identified', 'size_gb']\n", - "\n", - "mask = ((df_meta[cols[0]] < 20_000) & (df_meta[cols[1]] > 3.5)\n", - " | (df_meta[cols[1]] > 5)\n", - " )\n", - "\n", - "cols = ['Peptide Sequences Identified', 'size_gb']\n", - "ax = (df_meta\n", - " .loc[~mask, cols]\n", - " .plot\n", - " .scatter(cols[0], cols[1],\n", - " label='large files',\n", - " s=2,\n", - " )\n", - " )\n", - "ax = (df_meta\n", - " .loc[mask, cols]\n", - " .plot\n", - " .scatter(cols[0], cols[1],\n", - " color='orange',\n", - " label='normal files',\n", - " ylabel='filesize (in GB)',\n", - " ax=ax,\n", - " s=2,\n", - " )\n", - " )\n", - "ax.xaxis.set_major_formatter(\"{x:,.0f}\")\n", - "fname = out_folder / 'filesize_vs_iden_peptides.pdf'\n", - "files_out[fname.name] = fname.as_posix()\n", - "vaep.savefig(ax.get_figure(), fname)\n", - "\n", - "\n", - "view = df_meta.loc[mask].sort_values(by=cols)\n", - "view.to_excel(excel_writer, sheet_name='instrument_outliers', **writer_args)\n", - "view" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c718ce51", - "metadata": {}, - "outputs": [], - "source": [ - "cols = ['Number of MS1 spectra', 'Number of MS2 spectra',\n", - " 'Peptide Sequences Identified']\n", - "cols = vaep.pandas.get_columns_accessor_from_iterable(cols)\n", - "\n", - "view = df_meta.loc[mask_top10_instruments]\n", - "view[\"instrument_label+N\"] = view[\"instrument_label\"].replace(\n", - " counts_instrument.to_frame().apply(\n", - " lambda s: f\"{s.name} (N={s['count']:03d})\", axis=1))\n", - "view" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f55d77d2", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "fig, ax = plt.subplots()\n", - "\n", - "ax = seaborn.scatterplot(view,\n", - " x=cols.Number_of_MS1_spectra,\n", - " y=cols.Number_of_MS2_spectra,\n", - " hue='instrument_label+N',\n", - " legend='brief',\n", - " ax=ax,\n", - " s=5,\n", - " palette='deep')\n", - "_ = ax.legend(fontsize=5,\n", - " title_fontsize=5,\n", - " markerscale=0.4,\n", - " title='instrument label',\n", - " loc='upper right',\n", - " # alignment='left',\n", - " )\n", - "ax.xaxis.set_major_formatter(\"{x:,.0f}\")\n", - "ax.yaxis.set_major_formatter(\"{x:,.0f}\")\n", - "fname = out_folder / 'ms1_to_ms2_top10_instruments.pdf'\n", - "files_out[fname.name] = fname.as_posix()\n", - "vaep.savefig(fig, fname)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e8873c50", - "metadata": {}, - "outputs": [], - "source": [ - "fig, ax = plt.subplots()\n", - "ax = view.plot.scatter(x=cols.Peptide_Sequences_Identified,\n", - " y=cols.Number_of_MS1_spectra,\n", - " label=cols.Number_of_MS1_spectra,\n", - " s=2,\n", - " c='green',\n", - " ax=ax)\n", - "ax = view.plot.scatter(x=cols.Peptide_Sequences_Identified,\n", - " y=cols.Number_of_MS2_spectra,\n", - " label=cols.Number_of_MS2_spectra,\n", - " ylabel='# spectra',\n", - " s=2,\n", - " ax=ax)\n", - "fname = out_folder / 'ms1_vs_ms2.pdf'\n", - "ax.xaxis.set_major_formatter(\"{x:,.0f}\")\n", - "ax.yaxis.set_major_formatter(\"{x:,.0f}\")\n", - "files_out[fname.name] = fname.as_posix()\n", - "vaep.savefig(fig, fname)" - ] - }, - { - "cell_type": "markdown", - "id": "455debba", - "metadata": {}, - "source": [ - "## run length to number of identified peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5d50ea32", - "metadata": {}, - "outputs": [], - "source": [ - "df_meta.filter(like='RT', axis=1).describe()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2ef17002", - "metadata": {}, - "outputs": [], - "source": [ - "cols = ['MS max RT',\n", - " 'Peptide Sequences Identified']\n", - "cols = vaep.pandas.get_columns_accessor_from_iterable(cols)\n", - "\n", - "fig, ax = plt.subplots()\n", - "\n", - "ax = seaborn.scatterplot(\n", - " view,\n", - " x=cols.MS_max_RT,\n", - " y=cols.Peptide_Sequences_Identified,\n", - " hue='instrument_label+N',\n", - " legend='brief',\n", - " ax=ax,\n", - " s=5,\n", - " palette='deep')\n", - "_ = ax.legend(fontsize=5,\n", - " title_fontsize=5,\n", - " markerscale=0.4,\n", - " title='instrument label',\n", - " )\n", - "ax.yaxis.set_major_formatter(\"{x:,.0f}\")\n", - "fname = out_folder / 'RT_vs_identified_peptides_top10_instruments.pdf'\n", - "files_out[fname.name] = fname.as_posix()\n", - "vaep.savefig(ax.get_figure(), fname)" - ] - }, - { - "cell_type": "markdown", - "id": "e51b090d", - "metadata": {}, - "source": [ - "## Outputs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "219fb5c9", - "metadata": {}, - "outputs": [], - "source": [ - "excel_writer.close()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4eaaeba3", - "metadata": { - "lines_to_next_cell": 0 - }, - "outputs": [], - "source": [ - "files_out" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c79fa00", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "jupytext": { - "cell_metadata_filter": "incorrectly_encoded_metadata,-all", - "main_language": "python", - "notebook_metadata_filter": "-all" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/00_3_1_pride_metadata_analysis.py b/project/00_3_1_pride_metadata_analysis.py deleted file mode 100644 index 105a82d7a..000000000 --- a/project/00_3_1_pride_metadata_analysis.py +++ /dev/null @@ -1,314 +0,0 @@ -# %% - -# %% [markdown] -# ## Output Excel for Analysis - -# %% -from pathlib import Path -import matplotlib.pyplot as plt -import pandas as pd -import seaborn - - -from vaep.io import thermo_raw_files -import vaep.pandas - -plt.rcParams['figure.figsize'] = [4, 3] -vaep.plotting.make_large_descriptors(5) - - -# %% [tags=["parameters"]] -fn_meta = 'data/pride_metadata.csv' -date_col: str = 'Content Creation Date' -out_folder: str = 'data/dev_datasets/pride_upload' - -# %% [markdown] -# ## Prepare outputs - -# %% -out_folder = Path(out_folder) -out_folder.mkdir(exist_ok=True) -files_out = dict() - -# %% -df_meta = pd.read_csv(fn_meta, index_col=0) -df_meta - -# %% - -df_meta['instrument_label'] = ( - df_meta["Thermo Scientific instrument model"].str.replace(' ', '-') - + '_' - + df_meta["instrument serial number"].str.split('#').str[-1] -) - -# {k: k.replace('-Orbitrap_', ' ').replace('-', ' ').replace('_', ' ') -# for k in df_meta['instrument_label'].unique()} -# further small changes applied manually -# based on https://www.ebi.ac.uk/ols4/ -# -# Q Exactive HF-X MS:1002877 -# Q Exactive HF MS:1002523 -# Orbitrap Exploris 480 MS:1003028 -# Exactive Plus MS:1002526 -# Q Exactive MS:1001911 -# Orbitrap Fusion Lumos MS:1002732 - -instrument_labels = {'Q-Exactive-Orbitrap_1': 'Q Exactive 1', - 'Q-Exactive-Plus-Orbitrap_1': 'Exactive Plus 1', - 'Q-Exactive-HF-Orbitrap_206': 'Q Exactive HF 206', - 'Q-Exactive-Plus-Orbitrap_143': 'Exactive Plus 143', - 'Q-Exactive-HF-Orbitrap_1': 'Q Exactive HF 1', - 'Q-Exactive-HF-Orbitrap_147': 'Q Exactive HF 147', - 'Q-Exactive-HF-Orbitrap_204': 'Q Exactive HF 204', - 'Q-Exactive-HF-Orbitrap_148': 'Q Exactive HF 148', - 'Q-Exactive-HF-Orbitrap_207': 'Q Exactive HF 207', - 'Q-Exactive-HF-Orbitrap_143': 'Q Exactive HF 143', - 'Orbitrap-Fusion-Lumos_FSN20115': 'Orbitrap Fusion Lumos FSN20115', - 'Q-Exactive-HF-Orbitrap_2612': 'Q Exactive HF 2612', - 'Q-Exactive-HF-X-Orbitrap_6016': 'Q Exactive HF-X 6016', - 'Q-Exactive-HF-X-Orbitrap_6004': 'Q Exactive HF-X 6004', - 'Q-Exactive-HF-X-Orbitrap_6075': 'Q Exactive HF-X 6075', - 'Q-Exactive-HF-X-Orbitrap_6078': 'Q Exactive HF-X 6078', - 'Q-Exactive-HF-X-Orbitrap_6070': 'Q Exactive HF-X 6070', - 'Q-Exactive-HF-X-Orbitrap_6071': 'Q Exactive HF-X 6071', - 'Q-Exactive-HF-X-Orbitrap_6011': 'Q Exactive HF-X 6011', - 'Q-Exactive-HF-X-Orbitrap_6073': 'Q Exactive HF-X 6073', - 'Q-Exactive-HF-X-Orbitrap_6101': 'Q Exactive HF-X 6101', - 'Q-Exactive-HF-X-Orbitrap_6096': 'Q Exactive HF-X 6096', - 'Exactive-Series-Orbitrap_6004': 'Exactive Series 6004', - 'Q-Exactive-HF-X-Orbitrap_6043': 'Q Exactive HF-X 6043', - 'Q-Exactive-HF-X-Orbitrap_6025': 'Q Exactive HF-X 6025', - 'Q-Exactive-HF-X-Orbitrap_6022': 'Q Exactive HF-X 6022', - 'Q-Exactive-HF-X-Orbitrap_6023': 'Q Exactive HF-X 6023', - 'Q-Exactive-HF-X-Orbitrap_6028': 'Q Exactive HF-X 6028', - 'Q-Exactive-HF-X-Orbitrap_6013': 'Q Exactive HF-X 6013', - 'Q-Exactive-HF-X-Orbitrap_6044': 'Q Exactive HF-X 6044', - 'Q-Exactive-HF-X-Orbitrap_6324': 'Q Exactive HF-X 6324', - 'Orbitrap-Exploris-480_Invalid_SN_0001': 'Orbitrap Exploris 480 Invalid SN 0001', - 'Orbitrap-Exploris-480_MA10134C': 'Orbitrap Exploris 480 MA10134C', - 'Orbitrap-Exploris-480_MA10132C': 'Orbitrap Exploris 480 MA10132C', - 'Orbitrap-Exploris-480_MA10130C': 'Orbitrap Exploris 480 MA10130C', - 'Orbitrap-Exploris-480_MA10215C': 'Orbitrap Exploris 480 MA10215C'} - -df_meta["instrument_label"] = df_meta["instrument_label"].replace(instrument_labels) - -# %% -writer_args = dict(float_format='%.3f') -fname = out_folder / 'pride_data_infos.xlsx' -files_out[fname.name] = fname.as_posix() -excel_writer = pd.ExcelWriter(fname) - -# %% [markdown] -# ## Varying data between runs - -# %% -meta_stats = df_meta.describe(include='all') -meta_stats.T.to_excel(excel_writer, sheet_name='des_stats', **writer_args) - -view = meta_stats.loc[:, (meta_stats.loc['unique'] > 1) - | (meta_stats.loc['std'] > 0.01)].T -view.to_excel(excel_writer, sheet_name='des_stats_varying', **writer_args) - -# %% [markdown] -# ## Instruments in selection - -# %% -thermo_raw_files.cols_instrument - -# %% -df_meta[date_col] = pd.to_datetime(df_meta[date_col]) - -counts_instrument = (df_meta - .groupby(thermo_raw_files.cols_instrument)[date_col] - .agg(['count', 'min', 'max']) - .sort_values(by=thermo_raw_files.cols_instrument[:2] + ['count'], ascending=False)) - -counts_instrument = counts_instrument.join( - (df_meta - [[*thermo_raw_files.cols_instrument, 'instrument_label']] - .drop_duplicates() - .set_index(thermo_raw_files.cols_instrument) - ) - .set_index('instrument_label', append=True) -) -counts_instrument.to_excel( - excel_writer, sheet_name='instruments', **writer_args) -counts_instrument - -# %% -top10_instruments = counts_instrument['count'].nlargest(10) -top10_instruments - -# %% -mask_top10_instruments = (df_meta[thermo_raw_files.cols_instrument] - .apply( - lambda x: tuple(x) in top10_instruments.index, axis=1)) -assert mask_top10_instruments.sum() == top10_instruments.sum() - - -# %% -# counts_instrument = (df_meta -# .groupby(['instrument_label'])[date_col] -# .agg(['count', 'min', 'max']) -# .sort_values('count', ascending=False) -# ) -counts_instrument = (counts_instrument - .reset_index() - .set_index('instrument_label') - ['count'] - .sort_values(ascending=False) - ) -counts_instrument - -# %% -fig, ax = plt.subplots() -ax = (counts_instrument - .plot - .bar( - ax=ax, - ) - ) -ax.set_xlabel('') -ax.set_ylabel('number of samples (runs)') -fname = out_folder / 'number_of_samples_per_instrument.pdf' -files_out[fname.name] = fname.as_posix() -vaep.savefig(fig, fname) - -# %% [markdown] -# ## File size and number of identifications - -# %% -cols = ['Peptide Sequences Identified', 'size_gb'] - -mask = ((df_meta[cols[0]] < 20_000) & (df_meta[cols[1]] > 3.5) - | (df_meta[cols[1]] > 5) - ) - -cols = ['Peptide Sequences Identified', 'size_gb'] -ax = (df_meta - .loc[~mask, cols] - .plot - .scatter(cols[0], cols[1], - label='large files', - s=2, - ) - ) -ax = (df_meta - .loc[mask, cols] - .plot - .scatter(cols[0], cols[1], - color='orange', - label='normal files', - ylabel='filesize (in GB)', - ax=ax, - s=2, - ) - ) -ax.xaxis.set_major_formatter("{x:,.0f}") -fname = out_folder / 'filesize_vs_iden_peptides.pdf' -files_out[fname.name] = fname.as_posix() -vaep.savefig(ax.get_figure(), fname) - - -view = df_meta.loc[mask].sort_values(by=cols) -view.to_excel(excel_writer, sheet_name='instrument_outliers', **writer_args) -view - -# %% -cols = ['Number of MS1 spectra', 'Number of MS2 spectra', - 'Peptide Sequences Identified'] -cols = vaep.pandas.get_columns_accessor_from_iterable(cols) - -view = df_meta.loc[mask_top10_instruments] -view["instrument_label+N"] = view["instrument_label"].replace( - counts_instrument.to_frame().apply( - lambda s: f"{s.name} (N={s['count']:03d})", axis=1)) -view - -# %% -fig, ax = plt.subplots() - -ax = seaborn.scatterplot(view, - x=cols.Number_of_MS1_spectra, - y=cols.Number_of_MS2_spectra, - hue='instrument_label+N', - legend='brief', - ax=ax, - s=5, - palette='deep') -_ = ax.legend(fontsize=5, - title_fontsize=5, - markerscale=0.4, - title='instrument label', - loc='upper right', - # alignment='left', - ) -ax.xaxis.set_major_formatter("{x:,.0f}") -ax.yaxis.set_major_formatter("{x:,.0f}") -fname = out_folder / 'ms1_to_ms2_top10_instruments.pdf' -files_out[fname.name] = fname.as_posix() -vaep.savefig(fig, fname) - - -# %% -fig, ax = plt.subplots() -ax = view.plot.scatter(x=cols.Peptide_Sequences_Identified, - y=cols.Number_of_MS1_spectra, - label=cols.Number_of_MS1_spectra, - s=2, - c='green', - ax=ax) -ax = view.plot.scatter(x=cols.Peptide_Sequences_Identified, - y=cols.Number_of_MS2_spectra, - label=cols.Number_of_MS2_spectra, - ylabel='# spectra', - s=2, - ax=ax) -fname = out_folder / 'ms1_vs_ms2.pdf' -ax.xaxis.set_major_formatter("{x:,.0f}") -ax.yaxis.set_major_formatter("{x:,.0f}") -files_out[fname.name] = fname.as_posix() -vaep.savefig(fig, fname) - -# %% [markdown] -# ## run length to number of identified peptides - -# %% -df_meta.filter(like='RT', axis=1).describe() - -# %% -cols = ['MS max RT', - 'Peptide Sequences Identified'] -cols = vaep.pandas.get_columns_accessor_from_iterable(cols) - -fig, ax = plt.subplots() - -ax = seaborn.scatterplot( - view, - x=cols.MS_max_RT, - y=cols.Peptide_Sequences_Identified, - hue='instrument_label+N', - legend='brief', - ax=ax, - s=5, - palette='deep') -_ = ax.legend(fontsize=5, - title_fontsize=5, - markerscale=0.4, - title='instrument label', - ) -ax.yaxis.set_major_formatter("{x:,.0f}") -fname = out_folder / 'RT_vs_identified_peptides_top10_instruments.pdf' -files_out[fname.name] = fname.as_posix() -vaep.savefig(ax.get_figure(), fname) - -# %% [markdown] -# ## Outputs - -# %% -excel_writer.close() - -# %% -files_out -# %% diff --git a/project/00_4_development_dataset_support.py b/project/00_4_development_dataset_support.py deleted file mode 100644 index 31c671c70..000000000 --- a/project/00_4_development_dataset_support.py +++ /dev/null @@ -1,51 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.14.5 -# kernelspec: -# display_name: vaep -# language: python -# name: python3 -# --- - -# %% [markdown] -# # Support of dumped data - -# %% -import numpy as np -import pandas as pd -import plotly.express as px - -import vaep # set formatting defaults - -# %% [markdown] -# ## Parameters - -# %% tags=["parameters"] -# Path to json support file -support_json: str = 'data\\dev_datasets\\df_intensities_proteinGroups_long\\Q_Exactive_HF_X_Orbitrap_6070_support.json' - -# %% [markdown] -# ## Completeness of samples - -# %% -support = pd.read_json(support_json, typ='series').sort_values().to_frame('no. of features') -support.head() - -# %% -support.describe(percentiles=np.linspace(0.1, 1, 10)) - -# %% -ax = support.plot(rot=90, figsize=(20, 10), legend=False) -ax.set_ylabel('number of features') -ax.yaxis.set_major_formatter("{x:,.0f}") - -# %% -px.line(support, height=1000) - -# %% [markdown] -# The one with very few identification are mainly fractions of entire samples diff --git a/project/00_4_hela_development_dataset_splitting.ipynb b/project/00_4_hela_development_dataset_splitting.ipynb deleted file mode 100644 index bdf50a5cd..000000000 --- a/project/00_4_hela_development_dataset_splitting.ipynb +++ /dev/null @@ -1,828 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Split up data into single datasets\n", - "\n", - "- create datasets per (set of) instruments for a specific experiments\n", - "- drop some samples based on quality criteria" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from pathlib import Path\n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib\n", - "import matplotlib.pyplot as plt\n", - "import matplotlib.dates\n", - "import seaborn as sns\n", - "\n", - "import umap\n", - "\n", - "from vaep.io import thermo_raw_files\n", - "from vaep.analyzers import analyzers\n", - "\n", - "from config import erda_dumps\n", - "from config import defaults\n", - "\n", - "import vaep\n", - "import vaep.io.filenames\n", - "from vaep.logging import setup_nb_logger\n", - "\n", - "logger = setup_nb_logger()\n", - "\n", - "FOLDER_DATA = defaults.FOLDER_DATA" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "vaep.plotting.make_large_descriptors()\n", - "FIGSIZE = (15, 10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Parameters" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "parameters" - ] - }, - "outputs": [], - "source": [ - "N_MIN_INSTRUMENT = 300\n", - "META_DATA: str = 'data/files_selected_metadata.csv'\n", - "FILE_EXT = 'pkl' # 'csv' or 'pkl'\n", - "SAMPLE_ID = 'Sample ID'\n", - "\n", - "DUMP: str = erda_dumps.FN_PROTEIN_GROUPS # Filepath to erda dump\n", - "OUT_NAME = 'protein group' # for legends labels\n", - "# DUMP: str = erda_dumps.FN_PEPTIDES\n", - "# OUT_NAME = 'peptide' # for legends labels\n", - "# DUMP: str = erda_dumps.FN_EVIDENCE\n", - "# OUT_NAME = 'precursor' # for legends labels\n", - "\n", - "FOLDER_DATASETS: str = f'dev_datasets/{DUMP.stem}'\n", - "\n", - "INSTRUMENT_LEGEND_TITLE = 'Q Exactive HF-X Orbitrap'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# FILE_EXT = 'csv'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Make sure output folder exists" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "DUMP = Path(DUMP) # set parameter from cli or yaml to Path\n", - "FOLDER_DATASETS = defaults.FOLDER_DATA / FOLDER_DATASETS\n", - "FOLDER_DATASETS.mkdir(exist_ok=True, parents=True)\n", - "logger.info(f\"Folder for datasets to be created: {FOLDER_DATASETS.absolute()}\")\n", - "\n", - "files_out = dict()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Dumps" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- load dumps\n", - "- load file to machine mappings" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data = pd.read_pickle(DUMP)\n", - "data = data.squeeze() # In case it is a DataFrame, not a series (-> leads to MultiIndex)\n", - "# name_data = data.name\n", - "logger.info(\n", - " f\"Number of rows (row = sample, feature, intensity): {len(data):,d}\")\n", - "data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Make categorical index a normal string index (this lead to problems when selecting data using `loc` and grouping data as level of data could not easily be removed from MultiIndex)\n", - "\n", - "- see [blog](https://towardsdatascience.com/staying-sane-while-adopting-pandas-categorical-datatypes-78dbd19dcd8a)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# index_columns = data.index.names\n", - "# data = data.reset_index()\n", - "# print(data.memory_usage(deep=True))\n", - "# cat_columns = data.columns[data.dtypes == 'category']\n", - "# if not cat_columns.empty:\n", - "# data[cat_columns] = data[cat_columns].astype('object')\n", - "# print(\"non categorical: \\n\", data.memory_usage(deep=True))\n", - "# logger.warning(\n", - "# \"if time allows, this should be investigate -> use of loc with data which is not categorical\")\n", - "# data = data.set_index(index_columns)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# feat_name = list(data.index.names)\n", - "# feat_name.remove(SAMPLE_ID)\n", - "feat_name = (OUT_NAME,)\n", - "feat_name # index name(s) which are not the sample index" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# M = len(data.index.levels[-1])\n", - "N, M = data.shape\n", - "logger.info(f\"Number of unqiue features: {M}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Filter data by metadata" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# sample_ids = data.index.levels[0] # assume first index position is Sample ID?\n", - "sample_ids = data.index.unique() # .get_level_values(SAMPLE_ID).unique() # more explict\n", - "sample_ids" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "lines_to_next_cell": 0 - }, - "source": [ - "### Meta Data\n", - "\n", - "- based on ThermoRawFileParser" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_meta = pd.read_csv(META_DATA, index_col=SAMPLE_ID)\n", - "date_col = 'Content Creation Date'\n", - "df_meta[date_col] = pd.to_datetime(df_meta[date_col])\n", - "df_meta = df_meta.loc[sample_ids]\n", - "df_meta" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "lines_to_next_cell": 0 - }, - "source": [ - "## Rename samples\n", - "- to \"YEAR_MONTH_DAY_HOUR_MIN_INSTRUMENT\" (no encoding of information intended)\n", - "- check that instrument names are unique\n", - "- drop metadata (entire)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "lines_to_next_cell": 0 - }, - "outputs": [], - "source": [ - "idx_all = (pd.to_datetime(df_meta[\"Content Creation Date\"]).dt.strftime(\"%Y_%m_%d_%H_%M\")\n", - " + '_'\n", - " + df_meta[\"Thermo Scientific instrument model\"].str.replace(' ', '-')\n", - " + '_'\n", - " + df_meta[\"instrument serial number\"].str.split('#').str[-1])\n", - "\n", - "mask = idx_all.duplicated(keep=False)\n", - "duplicated_sample_idx = idx_all.loc[mask].sort_values() # duplicated dumps\n", - "duplicated_sample_idx\n", - "\n", - "#" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_duplicates = data.loc[duplicated_sample_idx.index] # .unstack()\n", - "# data_duplicates.T.corr() # same samples are have corr. of 1\n", - "data_duplicates.sum(axis=1) # keep only one seems okay" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "idx_unique = idx_all.drop_duplicates()\n", - "idx_unique" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_meta = df_meta.loc[idx_unique.index].rename(idx_unique)\n", - "df_meta" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# data = data.unstack(feat_name) # needed later anyways\n", - "data = data.loc[idx_unique.index].rename(idx_unique)\n", - "data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "meta_to_drop = ['Pathname']\n", - "fname = FOLDER_DATASETS / 'metadata.csv'\n", - "files_out[fname.name] = fname\n", - "df_meta.drop(meta_to_drop, axis=1).to_csv(fname)\n", - "logger.info(f\"{fname = }\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Support per sample in entire data set" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "counts = data.count(axis=1) # wide format\n", - "N = len(counts)\n", - "fname = FOLDER_DATASETS / 'support_all.json'\n", - "files_out[fname.name] = fname\n", - "counts.to_json(fname, indent=4)\n", - "ax = (counts\n", - " .sort_values() # will raise an error with a DataFrame\n", - " .reset_index(drop=True)\n", - " .plot(rot=45,\n", - " figsize=FIGSIZE,\n", - " grid=True,\n", - " ylabel='number of features in sample',\n", - " xlabel='Sample rank ordered by number of features',\n", - " title=f'Support of {N:,d} samples features over {M} features ({\", \".join(feat_name)})',\n", - " ))\n", - "vaep.plotting.add_prop_as_second_yaxis(ax, M)\n", - "fig = ax.get_figure()\n", - "fig.tight_layout()\n", - "fname = FOLDER_DATASETS / 'support_all.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.plotting.savefig(fig, fname)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "counts = data.count(axis=0) # wide format\n", - "counts.to_json(FOLDER_DATASETS / 'feat_completeness_all.json', indent=4)\n", - "ax = (counts\n", - " .sort_values() # will raise an error with a DataFrame\n", - " .reset_index(drop=True)\n", - " .plot(rot=45,\n", - " figsize=FIGSIZE,\n", - " grid=True,\n", - " ylabel='number of samples per feature',\n", - " xlabel='Feature rank ordered by number of samples',\n", - " title=f'Support of {len(counts):,d} features over {N} samples ({\", \".join(feat_name)})',\n", - " ))\n", - "vaep.plotting.add_prop_as_second_yaxis(ax, N)\n", - "fig = ax.get_figure()\n", - "fname = FOLDER_DATASETS / 'feat_per_sample_all.pdf'\n", - "files_out[fname.stem] = fname\n", - "vaep.plotting.savefig(fig, fname)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Available instruments" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "counts_instrument = df_meta.groupby(thermo_raw_files.cols_instrument)[date_col].agg(\n", - " ['count', 'min', 'max']).sort_values(by=thermo_raw_files.cols_instrument[:2] + ['count'], ascending=False)\n", - "counts_instrument" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "len(counts_instrument)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "selected_instruments = counts_instrument.query(f\"count >= {N_MIN_INSTRUMENT}\")\n", - "fname = FOLDER_DATASETS / 'dataset_info.xlsx'\n", - "files_out[fname.name] = fname\n", - "selected_instruments.to_latex(fname.with_suffix('.tex'))\n", - "selected_instruments.to_excel(fname)\n", - "logger.info(f\"Save Information to: {fname} (as xlsx and tex)\")\n", - "selected_instruments" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Summary plot - UMAP\n", - "\n", - "- embedding based on all samples\n", - "- visualization of top 5 instruments" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "reducer = umap.UMAP(random_state=42)\n", - "data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "embedding = reducer.fit_transform(data.fillna(data.median()))\n", - "embedding = pd.DataFrame(embedding, index=data.index,\n", - " columns=['UMAP 1', 'UMAP 2'])\n", - "embedding = embedding.join(\n", - " df_meta[[\"Content Creation Date\", \"instrument serial number\"]])\n", - "d_instrument_counts = counts_instrument['count'].reset_index(\n", - " level=[0, 1], drop=True).to_dict()\n", - "embedding[\"count\"] = embedding[\"instrument serial number\"].replace(\n", - " d_instrument_counts)\n", - "embedding" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "digits = int(np.ceil(np.log10(embedding[\"count\"].max())))\n", - "digits" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "embedding[\"instrument with N\"] = embedding[[\"instrument serial number\",\n", - " \"count\"]].apply(lambda s: f\"{s[0]} (N={s[1]:{digits}d})\", axis=1)\n", - "embedding[\"instrument with N\"] = embedding[\"instrument with N\"].str.replace(\n", - " 'Exactive Series slot', 'Instrument')\n", - "embedding" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "define top five instruments" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "top_5 = counts_instrument[\"count\"].nlargest(5)\n", - "top_5 = top_5.index.levels[-1]\n", - "embedding[\"instrument\"] = embedding[\"instrument serial number\"].apply(\n", - " lambda x: x if x in top_5 else 'other')\n", - "mask_top_5 = embedding[\"instrument\"] != 'other'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "embedding[\"Date (90 days intervals)\"] = embedding[\"Content Creation Date\"].dt.round(\n", - " \"90D\").astype(str)\n", - "to_plot = embedding.loc[mask_top_5]\n", - "print(f\"N samples in plot: {len(to_plot):,d}\")\n", - "fig, ax = plt.subplots(figsize=(20, 10))\n", - "\n", - "ax = sns.scatterplot(data=to_plot, x='UMAP 1', y='UMAP 2', style=\"instrument with N\",\n", - " hue=\"Date (90 days intervals)\", ax=ax) # =\"Content Creation Date\")\n", - "\n", - "fname = FOLDER_DATASETS / 'umap_interval90days_top5_instruments.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "markers = ['o', 'x', 's', 'P', 'D', '.']\n", - "alpha = 0.6\n", - "fig, ax = plt.subplots(figsize=(12, 8))\n", - "groups = list()\n", - "\n", - "vaep.plotting.make_large_descriptors()\n", - "embedding[\"Content Creation Date\"] = embedding[\"Content Creation Date\"].dt.round(\n", - " \"D\")\n", - "embedding[\"mdate\"] = embedding[\"Content Creation Date\"].apply(\n", - " matplotlib.dates.date2num)\n", - "\n", - "to_plot = embedding.loc[mask_top_5]\n", - "\n", - "norm = matplotlib.colors.Normalize(\n", - " embedding[\"mdate\"].quantile(0.05), embedding[\"mdate\"].quantile(0.95))\n", - "cmap = sns.color_palette(\"cubehelix\", as_cmap=True)\n", - "\n", - "\n", - "for k, _to_plot in to_plot.groupby('instrument with N'):\n", - " if markers:\n", - " marker = markers.pop(0)\n", - " _ = ax.scatter(\n", - " x=_to_plot[\"UMAP 1\"],\n", - " y=_to_plot[\"UMAP 2\"],\n", - " c=_to_plot[\"mdate\"],\n", - " alpha=alpha,\n", - " marker=marker,\n", - " cmap=cmap,\n", - " norm=norm\n", - " )\n", - " groups.append(k)\n", - "\n", - "cbar = vaep.analyzers.analyzers.add_date_colorbar(\n", - " ax.collections[0], ax=ax)\n", - "cbar.ax.set_ylabel(\"date of measurement\", labelpad=-115, loc='center')\n", - "ax.legend(ax.collections, groups,\n", - " title=INSTRUMENT_LEGEND_TITLE, fontsize='xx-large')\n", - "ax.set_xlabel('UMAP 1') # , fontdict={'size': 16})\n", - "ax.set_ylabel('UMAP 2')\n", - "\n", - "fname = FOLDER_DATASETS / 'umap_date_top5_instruments.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Summary statistics for top 5 instruments" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "fig, ax = plt.subplots(1, 1, figsize=(6, 6))\n", - "# boxplot: number of available sample for included features\n", - "to_plot = (data\n", - " .loc[mask_top_5]\n", - " .notna()\n", - " .sum(axis=0)\n", - " .reset_index(drop=True)\n", - " .to_frame(f'{OUT_NAME.capitalize()} prevalence')\n", - " )\n", - "# boxplot: number of features per sample\n", - "to_plot = (to_plot\n", - " .join(data\n", - " .loc[mask_top_5]\n", - " .notna()\n", - " .sum(axis=1)\n", - " .reset_index(drop=True)\n", - " .to_frame(f'{OUT_NAME.capitalize()}s per sample'))\n", - " )\n", - "to_plot = (to_plot\n", - " .join(counts_instrument\n", - " .reset_index([0, 1], drop=True)\n", - " .loc[top_5, 'count']\n", - " .reset_index(drop=True)\n", - " .rename('Samples per instrument', axis='index'))\n", - " )\n", - "ax = to_plot.plot(kind='box', ax=ax, fontsize=16, )\n", - "ax.set_ylabel('number of observations',\n", - " fontdict={'fontsize': 14})\n", - "ax.set_xticklabels(ax.get_xticklabels(), rotation=45,\n", - " horizontalalignment='right')\n", - "to_plot.to_csv(FOLDER_DATASETS / 'summary_statistics_dump_data.csv')\n", - "\n", - "fname = FOLDER_DATASETS / 'summary_statistics_dump.pdf'\n", - "files_out[fname.name] = fname\n", - "vaep.savefig(fig, name=fname)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "top_5_meta = df_meta.loc[mask_top_5]\n", - "top_5_meta[['injection volume setting', 'dilution factor']].describe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Meta data stats for top 5" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for _instrument, _df_meta_instrument in top_5_meta.groupby(by=thermo_raw_files.cols_instrument):\n", - " print('#' * 80, ' - '.join(_instrument), sep='\\n')\n", - " display(_df_meta_instrument.describe())\n", - " display(_df_meta_instrument['injection volume setting'].value_counts())\n", - " break" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Dump single experiments\n", - "\n", - "in wide format" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# data = data.stack(feat_name)\n", - "data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "cols = selected_instruments.index.names\n", - "\n", - "file_formats = {'pkl': 'to_pickle',\n", - " 'pickle': 'to_pickle',\n", - " 'csv': 'to_csv'}\n", - "\n", - "\n", - "for values in selected_instruments.index:\n", - " mask = df_meta[cols] == values\n", - " logger.info(f\"Samples: {mask.all(axis=1).sum()}\")\n", - " sample_ids = df_meta.loc[mask.all(axis=1)]\n", - " display(sample_ids.sort_index())\n", - " sample_ids = sample_ids.index\n", - " # which categorical this might need to be a categorical Index as well?\n", - " dataset = data.loc[sample_ids]\n", - " # dataset.index = dataset.index.remove_unused_levels()\n", - "\n", - " display(dataset\n", - " # .unstack(dataset.index.names[1:])\n", - " .sort_index()\n", - " )\n", - "\n", - " fname_dataset = vaep.io.get_fname_from_keys(values,\n", - " file_ext=f\".{FILE_EXT}\")\n", - " fname_dataset = (FOLDER_DATASETS /\n", - " fname_dataset.name.replace('Exactive_Series_slot_#', ''))\n", - " files_out[fname_dataset.name] = fname_dataset\n", - " logger.info(f'Dump dataset with N = {len(dataset)} to {fname_dataset}')\n", - " _to_file_format = getattr(dataset, file_formats[FILE_EXT])\n", - " _to_file_format(fname_dataset)\n", - "\n", - " # calculate support\n", - " counts = dataset.count(axis=1).squeeze()\n", - " # to disk\n", - " fname_support = vaep.io.get_fname_from_keys(values,\n", - " folder='.',\n", - " file_ext=\"\")\n", - " fname_support = (FOLDER_DATASETS /\n", - " (fname_support.stem + '_support.json').replace('Exactive_Series_slot_#', ''))\n", - " files_out[fname_support.name] = fname_support\n", - " logger.info(f\"Dump support to: {fname_support.as_posix()}\")\n", - "\n", - " counts.to_json(fname_support, indent=4)\n", - "\n", - " # very slow alternative, but 100% correct\n", - " # M = dataset.index.droplevel(SAMPLE_ID).nunique()\n", - " N, M = dataset.shape\n", - "\n", - " # plot support:\n", - " fig, ax = plt.subplots()\n", - " ax = (counts\n", - " .sort_values() # will raise an error with a DataFrame\n", - " .reset_index(drop=True)\n", - " .plot(rot=45,\n", - " ax=ax,\n", - " figsize=FIGSIZE,\n", - " grid=True,\n", - " xlabel='Count of samples ordered by number of features',\n", - " title=f'Support of {len(counts):,d} samples features over {M} features ({\", \".join(feat_name)})',\n", - " ))\n", - " vaep.plotting.add_prop_as_second_yaxis(ax, M)\n", - " fig.tight_layout()\n", - " fname_support = fname_support.with_suffix('.pdf')\n", - " files_out[fname_support.name] = fname_support\n", - " vaep.plotting.savefig(fig, name=fname_support)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Last example dumped" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dataset" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# add json dump as target file for script for workflows\n", - "fname = FOLDER_DATASETS / 'selected_instruments.json'\n", - "files_out[fname.name] = fname\n", - "selected_instruments.to_json(fname, indent=4)\n", - "logger.info(f\"Saved: {fname}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "files_out" - ] - } - ], - "metadata": { - "interpreter": { - "hash": "cf83e9cb890c7f96eb0ae04f39a82254555f56a1a0ed2f03b23a8b40fe6cd31c" - }, - "kernelspec": { - "display_name": "Python 3", - "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.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/00_4_hela_development_dataset_splitting.py b/project/00_4_hela_development_dataset_splitting.py deleted file mode 100644 index 5cba7438c..000000000 --- a/project/00_4_hela_development_dataset_splitting.py +++ /dev/null @@ -1,505 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: Python 3 -# language: python -# name: python3 -# --- - -# %% [markdown] -# # Split up data into single datasets -# -# - create datasets per (set of) instruments for a specific experiments -# - drop some samples based on quality criteria - -# %% -from pathlib import Path - -import numpy as np -import pandas as pd -import matplotlib -import matplotlib.pyplot as plt -import matplotlib.dates -import seaborn as sns - -import umap - -from vaep.io import thermo_raw_files -from vaep.analyzers import analyzers - -from config import erda_dumps -from config import defaults - -import vaep -import vaep.io.filenames -from vaep.logging import setup_nb_logger - -logger = setup_nb_logger() - -FOLDER_DATA = defaults.FOLDER_DATA - -# %% -vaep.plotting.make_large_descriptors() -FIGSIZE = (15, 10) - -# %% [markdown] -# ## Parameters - -# %% tags=["parameters"] -N_MIN_INSTRUMENT = 300 -META_DATA: str = 'data/files_selected_metadata.csv' -FILE_EXT = 'pkl' # 'csv' or 'pkl' -SAMPLE_ID = 'Sample ID' - -DUMP: str = erda_dumps.FN_PROTEIN_GROUPS # Filepath to erda dump -OUT_NAME = 'protein group' # for legends labels -# DUMP: str = erda_dumps.FN_PEPTIDES -# OUT_NAME = 'peptide' # for legends labels -# DUMP: str = erda_dumps.FN_EVIDENCE -# OUT_NAME = 'precursor' # for legends labels - -FOLDER_DATASETS: str = f'dev_datasets/{DUMP.stem}' - -INSTRUMENT_LEGEND_TITLE = 'Q Exactive HF-X Orbitrap' - -# %% -# FILE_EXT = 'csv' - -# %% [markdown] -# Make sure output folder exists - -# %% -DUMP = Path(DUMP) # set parameter from cli or yaml to Path -FOLDER_DATASETS = defaults.FOLDER_DATA / FOLDER_DATASETS -FOLDER_DATASETS.mkdir(exist_ok=True, parents=True) -logger.info(f"Folder for datasets to be created: {FOLDER_DATASETS.absolute()}") - -files_out = dict() - -# %% [markdown] -# ## Dumps - -# %% [markdown] -# - load dumps -# - load file to machine mappings - -# %% -data = pd.read_pickle(DUMP) -data = data.squeeze() # In case it is a DataFrame, not a series (-> leads to MultiIndex) -# name_data = data.name -logger.info( - f"Number of rows (row = sample, feature, intensity): {len(data):,d}") -data - -# %% [markdown] -# Make categorical index a normal string index (this lead to problems when selecting data using `loc` and grouping data as level of data could not easily be removed from MultiIndex) -# -# - see [blog](https://towardsdatascience.com/staying-sane-while-adopting-pandas-categorical-datatypes-78dbd19dcd8a) - -# %% -# index_columns = data.index.names -# data = data.reset_index() -# print(data.memory_usage(deep=True)) -# cat_columns = data.columns[data.dtypes == 'category'] -# if not cat_columns.empty: -# data[cat_columns] = data[cat_columns].astype('object') -# print("non categorical: \n", data.memory_usage(deep=True)) -# logger.warning( -# "if time allows, this should be investigate -> use of loc with data which is not categorical") -# data = data.set_index(index_columns) - -# %% -# feat_name = list(data.index.names) -# feat_name.remove(SAMPLE_ID) -feat_name = (OUT_NAME,) -feat_name # index name(s) which are not the sample index - -# %% -# M = len(data.index.levels[-1]) -N, M = data.shape -logger.info(f"Number of unqiue features: {M}") - -# %% [markdown] -# ## Filter data by metadata - -# %% -# sample_ids = data.index.levels[0] # assume first index position is Sample ID? -sample_ids = data.index.unique() # .get_level_values(SAMPLE_ID).unique() # more explict -sample_ids - -# %% [markdown] -# ### Meta Data -# -# - based on ThermoRawFileParser -# %% -df_meta = pd.read_csv(META_DATA, index_col=SAMPLE_ID) -date_col = 'Content Creation Date' -df_meta[date_col] = pd.to_datetime(df_meta[date_col]) -df_meta = df_meta.loc[sample_ids] -df_meta - -# %% [markdown] -# ## Rename samples -# - to "YEAR_MONTH_DAY_HOUR_MIN_INSTRUMENT" (no encoding of information intended) -# - check that instrument names are unique -# - drop metadata (entire) -# %% -idx_all = (pd.to_datetime(df_meta["Content Creation Date"]).dt.strftime("%Y_%m_%d_%H_%M") - + '_' - + df_meta["Thermo Scientific instrument model"].str.replace(' ', '-') - + '_' - + df_meta["instrument serial number"].str.split('#').str[-1]) - -mask = idx_all.duplicated(keep=False) -duplicated_sample_idx = idx_all.loc[mask].sort_values() # duplicated dumps -duplicated_sample_idx - -# -# %% -data_duplicates = data.loc[duplicated_sample_idx.index] # .unstack() -# data_duplicates.T.corr() # same samples are have corr. of 1 -data_duplicates.sum(axis=1) # keep only one seems okay - -# %% -idx_unique = idx_all.drop_duplicates() -idx_unique - -# %% -df_meta = df_meta.loc[idx_unique.index].rename(idx_unique) -df_meta - -# %% -# data = data.unstack(feat_name) # needed later anyways -data = data.loc[idx_unique.index].rename(idx_unique) -data - -# %% -meta_to_drop = ['Pathname'] -fname = FOLDER_DATASETS / 'metadata.csv' -files_out[fname.name] = fname -df_meta.drop(meta_to_drop, axis=1).to_csv(fname) -logger.info(f"{fname = }") - - -# %% [markdown] -# ## Support per sample in entire data set - -# %% -counts = data.count(axis=1) # wide format -N = len(counts) -fname = FOLDER_DATASETS / 'support_all.json' -files_out[fname.name] = fname -counts.to_json(fname, indent=4) -ax = (counts - .sort_values() # will raise an error with a DataFrame - .reset_index(drop=True) - .plot(rot=45, - figsize=FIGSIZE, - grid=True, - ylabel='number of features in sample', - xlabel='Sample rank ordered by number of features', - title=f'Support of {N:,d} samples features over {M} features ({", ".join(feat_name)})', - )) -vaep.plotting.add_prop_as_second_yaxis(ax, M) -fig = ax.get_figure() -fig.tight_layout() -fname = FOLDER_DATASETS / 'support_all.pdf' -files_out[fname.name] = fname -vaep.plotting.savefig(fig, fname) - - -# %% -counts = data.count(axis=0) # wide format -counts.to_json(FOLDER_DATASETS / 'feat_completeness_all.json', indent=4) -ax = (counts - .sort_values() # will raise an error with a DataFrame - .reset_index(drop=True) - .plot(rot=45, - figsize=FIGSIZE, - grid=True, - ylabel='number of samples per feature', - xlabel='Feature rank ordered by number of samples', - title=f'Support of {len(counts):,d} features over {N} samples ({", ".join(feat_name)})', - )) -vaep.plotting.add_prop_as_second_yaxis(ax, N) -fig = ax.get_figure() -fname = FOLDER_DATASETS / 'feat_per_sample_all.pdf' -files_out[fname.stem] = fname -vaep.plotting.savefig(fig, fname) - - -# %% [markdown] -# ## Available instruments - -# %% -counts_instrument = df_meta.groupby(thermo_raw_files.cols_instrument)[date_col].agg( - ['count', 'min', 'max']).sort_values(by=thermo_raw_files.cols_instrument[:2] + ['count'], ascending=False) -counts_instrument - -# %% -len(counts_instrument) - -# %% -selected_instruments = counts_instrument.query(f"count >= {N_MIN_INSTRUMENT}") -fname = FOLDER_DATASETS / 'dataset_info.xlsx' -files_out[fname.name] = fname -selected_instruments.to_latex(fname.with_suffix('.tex')) -selected_instruments.to_excel(fname) -logger.info(f"Save Information to: {fname} (as xlsx and tex)") -selected_instruments - - -# %% [markdown] -# ## Summary plot - UMAP -# -# - embedding based on all samples -# - visualization of top 5 instruments - -# %% -reducer = umap.UMAP(random_state=42) -data - -# %% -embedding = reducer.fit_transform(data.fillna(data.median())) -embedding = pd.DataFrame(embedding, index=data.index, - columns=['UMAP 1', 'UMAP 2']) -embedding = embedding.join( - df_meta[["Content Creation Date", "instrument serial number"]]) -d_instrument_counts = counts_instrument['count'].reset_index( - level=[0, 1], drop=True).to_dict() -embedding["count"] = embedding["instrument serial number"].replace( - d_instrument_counts) -embedding - -# %% -digits = int(np.ceil(np.log10(embedding["count"].max()))) -digits - -# %% -embedding["instrument with N"] = embedding[["instrument serial number", - "count"]].apply(lambda s: f"{s[0]} (N={s[1]:{digits}d})", axis=1) -embedding["instrument with N"] = embedding["instrument with N"].str.replace( - 'Exactive Series slot', 'Instrument') -embedding - -# %% [markdown] -# define top five instruments - -# %% -top_5 = counts_instrument["count"].nlargest(5) -top_5 = top_5.index.levels[-1] -embedding["instrument"] = embedding["instrument serial number"].apply( - lambda x: x if x in top_5 else 'other') -mask_top_5 = embedding["instrument"] != 'other' - -# %% -embedding["Date (90 days intervals)"] = embedding["Content Creation Date"].dt.round( - "90D").astype(str) -to_plot = embedding.loc[mask_top_5] -print(f"N samples in plot: {len(to_plot):,d}") -fig, ax = plt.subplots(figsize=(20, 10)) - -ax = sns.scatterplot(data=to_plot, x='UMAP 1', y='UMAP 2', style="instrument with N", - hue="Date (90 days intervals)", ax=ax) # ="Content Creation Date") - -fname = FOLDER_DATASETS / 'umap_interval90days_top5_instruments.pdf' -files_out[fname.name] = fname -vaep.savefig(fig, name=fname) - -# %% -markers = ['o', 'x', 's', 'P', 'D', '.'] -alpha = 0.6 -fig, ax = plt.subplots(figsize=(12, 8)) -groups = list() - -vaep.plotting.make_large_descriptors() -embedding["Content Creation Date"] = embedding["Content Creation Date"].dt.round( - "D") -embedding["mdate"] = embedding["Content Creation Date"].apply( - matplotlib.dates.date2num) - -to_plot = embedding.loc[mask_top_5] - -norm = matplotlib.colors.Normalize( - embedding["mdate"].quantile(0.05), embedding["mdate"].quantile(0.95)) -cmap = sns.color_palette("cubehelix", as_cmap=True) - - -for k, _to_plot in to_plot.groupby('instrument with N'): - if markers: - marker = markers.pop(0) - _ = ax.scatter( - x=_to_plot["UMAP 1"], - y=_to_plot["UMAP 2"], - c=_to_plot["mdate"], - alpha=alpha, - marker=marker, - cmap=cmap, - norm=norm - ) - groups.append(k) - -cbar = vaep.analyzers.analyzers.add_date_colorbar( - ax.collections[0], ax=ax) -cbar.ax.set_ylabel("date of measurement", labelpad=-115, loc='center') -ax.legend(ax.collections, groups, - title=INSTRUMENT_LEGEND_TITLE, fontsize='xx-large') -ax.set_xlabel('UMAP 1') # , fontdict={'size': 16}) -ax.set_ylabel('UMAP 2') - -fname = FOLDER_DATASETS / 'umap_date_top5_instruments.pdf' -files_out[fname.name] = fname -vaep.savefig(fig, name=fname) - -# %% [markdown] -# ## Summary statistics for top 5 instruments - -# %% -fig, ax = plt.subplots(1, 1, figsize=(6, 6)) -# boxplot: number of available sample for included features -to_plot = (data - .loc[mask_top_5] - .notna() - .sum(axis=0) - .reset_index(drop=True) - .to_frame(f'{OUT_NAME.capitalize()} prevalence') - ) -# boxplot: number of features per sample -to_plot = (to_plot - .join(data - .loc[mask_top_5] - .notna() - .sum(axis=1) - .reset_index(drop=True) - .to_frame(f'{OUT_NAME.capitalize()}s per sample')) - ) -to_plot = (to_plot - .join(counts_instrument - .reset_index([0, 1], drop=True) - .loc[top_5, 'count'] - .reset_index(drop=True) - .rename('Samples per instrument', axis='index')) - ) -ax = to_plot.plot(kind='box', ax=ax, fontsize=16, ) -ax.set_ylabel('number of observations', - fontdict={'fontsize': 14}) -ax.set_xticklabels(ax.get_xticklabels(), rotation=45, - horizontalalignment='right') -to_plot.to_csv(FOLDER_DATASETS / 'summary_statistics_dump_data.csv') - -fname = FOLDER_DATASETS / 'summary_statistics_dump.pdf' -files_out[fname.name] = fname -vaep.savefig(fig, name=fname) - - -# %% -top_5_meta = df_meta.loc[mask_top_5] -top_5_meta[['injection volume setting', 'dilution factor']].describe() - -# %% [markdown] -# ### Meta data stats for top 5 - -# %% -for _instrument, _df_meta_instrument in top_5_meta.groupby(by=thermo_raw_files.cols_instrument): - print('#' * 80, ' - '.join(_instrument), sep='\n') - display(_df_meta_instrument.describe()) - display(_df_meta_instrument['injection volume setting'].value_counts()) - break - -# %% [markdown] -# ## Dump single experiments -# -# in wide format - -# %% -# data = data.stack(feat_name) -data - -# %% -cols = selected_instruments.index.names - -file_formats = {'pkl': 'to_pickle', - 'pickle': 'to_pickle', - 'csv': 'to_csv'} - - -for values in selected_instruments.index: - mask = df_meta[cols] == values - logger.info(f"Samples: {mask.all(axis=1).sum()}") - sample_ids = df_meta.loc[mask.all(axis=1)] - display(sample_ids.sort_index()) - sample_ids = sample_ids.index - # which categorical this might need to be a categorical Index as well? - dataset = data.loc[sample_ids] - # dataset.index = dataset.index.remove_unused_levels() - - display(dataset - # .unstack(dataset.index.names[1:]) - .sort_index() - ) - - fname_dataset = vaep.io.get_fname_from_keys(values, - file_ext=f".{FILE_EXT}") - fname_dataset = (FOLDER_DATASETS / - fname_dataset.name.replace('Exactive_Series_slot_#', '')) - files_out[fname_dataset.name] = fname_dataset - logger.info(f'Dump dataset with N = {len(dataset)} to {fname_dataset}') - _to_file_format = getattr(dataset, file_formats[FILE_EXT]) - _to_file_format(fname_dataset) - - # calculate support - counts = dataset.count(axis=1).squeeze() - # to disk - fname_support = vaep.io.get_fname_from_keys(values, - folder='.', - file_ext="") - fname_support = (FOLDER_DATASETS / - (fname_support.stem + '_support.json').replace('Exactive_Series_slot_#', '')) - files_out[fname_support.name] = fname_support - logger.info(f"Dump support to: {fname_support.as_posix()}") - - counts.to_json(fname_support, indent=4) - - # very slow alternative, but 100% correct - # M = dataset.index.droplevel(SAMPLE_ID).nunique() - N, M = dataset.shape - - # plot support: - fig, ax = plt.subplots() - ax = (counts - .sort_values() # will raise an error with a DataFrame - .reset_index(drop=True) - .plot(rot=45, - ax=ax, - figsize=FIGSIZE, - grid=True, - xlabel='Count of samples ordered by number of features', - title=f'Support of {len(counts):,d} samples features over {M} features ({", ".join(feat_name)})', - )) - vaep.plotting.add_prop_as_second_yaxis(ax, M) - fig.tight_layout() - fname_support = fname_support.with_suffix('.pdf') - files_out[fname_support.name] = fname_support - vaep.plotting.savefig(fig, name=fname_support) - -# %% [markdown] -# ## Last example dumped - -# %% -dataset - -# %% -# add json dump as target file for script for workflows -fname = FOLDER_DATASETS / 'selected_instruments.json' -files_out[fname.name] = fname -selected_instruments.to_json(fname, indent=4) -logger.info(f"Saved: {fname}") - -# %% -files_out diff --git a/project/00_5_development_dataset_support.ipynb b/project/00_5_development_dataset_support.ipynb deleted file mode 100644 index 5d921944d..000000000 --- a/project/00_5_development_dataset_support.ipynb +++ /dev/null @@ -1,128 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "ea31410b-bc16-4cf4-9a0b-d48fd463b8ff", - "metadata": {}, - "source": [ - "# Support of dumped data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "22244800-d388-4395-a107-a6c5c2d5038f", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "import plotly.express as px\n", - "\n", - "import vaep # set formatting defaults" - ] - }, - { - "cell_type": "markdown", - "id": "5fe86eb0-ecda-46ef-9f1b-86fa1152a73d", - "metadata": {}, - "source": [ - "## Parameters" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b8220ff5-8af8-4881-9411-c9164576a9fb", - "metadata": { - "tags": [ - "parameters" - ] - }, - "outputs": [], - "source": [ - "support_json: str = 'data\\dev_datasets\\df_intensities_proteinGroups_long\\Q_Exactive_HF_X_Orbitrap_6070_support.json' # Path to json support file" - ] - }, - { - "cell_type": "markdown", - "id": "ebaf7373-cc81-4cfa-9dea-eb518c059c9a", - "metadata": {}, - "source": [ - "## Completeness of samples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "82710205-39ff-44da-a4fe-9fbdb489ef4d", - "metadata": {}, - "outputs": [], - "source": [ - "support = pd.read_json(support_json, typ='series').sort_values().to_frame('no. of features')\n", - "support.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4656af82", - "metadata": {}, - "outputs": [], - "source": [ - "support.describe(percentiles=np.linspace(0.1,1,10))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e623a270-4044-4b58-a0a5-036985cb5e38", - "metadata": {}, - "outputs": [], - "source": [ - "ax = support.plot(rot=90, figsize=(20,10), legend=False)\n", - "ax.set_ylabel('number of features')\n", - "ax.yaxis.set_major_formatter(\"{x:,.0f}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e60e883a-570c-430f-a7b7-dd4acc1fc4c8", - "metadata": {}, - "outputs": [], - "source": [ - "px.line(support, height=1000)" - ] - }, - { - "cell_type": "markdown", - "id": "dec709da-23c9-48bd-b233-1e0c6b3bf0c8", - "metadata": {}, - "source": [ - "The one with very few identification are mainly fractions of entire samples" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "vaep", - "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.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/00_6_hela_training_data_exploration.ipynb b/project/00_6_hela_training_data_exploration.ipynb deleted file mode 100644 index 856f3919d..000000000 --- a/project/00_6_hela_training_data_exploration.ipynb +++ /dev/null @@ -1,947 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "# Peptides\n", - "\n", - "Load peptides selected for training" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "from datetime import datetime\n", - "from functools import partial\n", - "from pathlib import Path\n", - "from random import sample\n", - "\n", - "import ipywidgets as w\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# from sklearn import preprocessing\n", - "# from sklearn.decomposition import PCA\n", - "import seaborn as sns\n", - "\n", - "import vaep\n", - "from vaep.data_handling import coverage\n", - "from vaep.plotting import _savefig\n", - "\n", - "import config\n", - "from vaep.analyzers import analyzers\n", - "from vaep.io.data_objects import PeptideCounter\n", - "from vaep.transform import log\n", - "\n", - "pd.options.display.max_columns = 100\n", - "pd.options.display.min_rows = 30" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Descriptive Statistics (Linear case)\n", - "\n", - "- spread of peptide quantifications between samples\n", - "- spread of quantifications within samples\n", - "- correlation analysis: can linear correlation be picked up?\n" - ] - }, - { - "cell_type": "markdown", - "id": "8b4a827b", - "metadata": {}, - "source": [ - "### Peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "FN_PEPTIDE_INTENSITIES = Path(\n", - " 'data/dev_datasets/df_intensities_proteinGroups_long_2017_2018_2019_2020_N05015_M04547/Q_Exactive_HF_X_Orbitrap_Exactive_Series_slot_#6070.csv')\n", - "FIGUREFOLDER = FN_PEPTIDE_INTENSITIES.parent / 'figures' / FN_PEPTIDE_INTENSITIES.stem\n", - "FIGUREFOLDER.mkdir(exist_ok=True, parents=True)\n", - "FIGUREFOLDER" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "858f0520", - "metadata": {}, - "outputs": [], - "source": [ - "N_FIRST_ROWS = None # possibility to select N first rows\n", - "analysis = analyzers.AnalyzePeptides.from_csv(fname=FN_PEPTIDE_INTENSITIES, index_col=[0, 1], nrows=N_FIRST_ROWS)\n", - "df = analysis.to_wide_format()\n", - "analysis.describe_peptides(sample_n=30)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Peptide frequency: sellect the N most common peptides\n", - "\n", - "- N most common peptides between samples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "N = 10\n", - "\n", - "peptide_counter = PeptideCounter(config.FNAME_C_PEPTIDES)\n", - "peptide_counter.counter.most_common(N)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "counts = analysis.df.count().sort_values(ascending=False)\n", - "counts.iloc[:N]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "analysis.df[counts.iloc[:N].index]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Correlation between peptides\n", - "- linear correlation as indicator that there is some variation which could be used by models (or other heuristics)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sample = analysis.df.sample(n=30, axis=1)\n", - "# ToDo func is assigned to df\n", - "corr_lower_triangle = analyzers.corr_lower_triangle(sample)\n", - "corr_lower_triangle" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "826033b0", - "metadata": {}, - "outputs": [], - "source": [ - "fig, axes = analyzers.plot_corr_histogram(corr_lower_triangle, bins=40)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Samples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "analysis.df.sample(30, axis=0).T.describe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Peptides (all)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "stats = analysis.describe_peptides()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f0b01a33", - "metadata": {}, - "outputs": [], - "source": [ - "# biological coefficient of variation: standard deviation (variation) w.r.t mean\n", - "_ = stats.loc['CV'].hist(figsize=(10, 4))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1e84e975", - "metadata": {}, - "outputs": [], - "source": [ - "_ = stats.loc['count'].hist(figsize=(10, 4))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8dca5410", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "INDEX_NAME = 'Sample ID'\n", - "analysis.df.index.name = INDEX_NAME" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0da26061", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "analysis.df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "60215da2", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "N_MIN_OBS = analysis.df.shape[0] * 0.7 # here: present in 70% of the samples\n", - "mask_min_obsevation = analysis.df.notna().sum() >= N_MIN_OBS\n", - "mask_min_obsevation.sum()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Reference analysis.df as `X`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "X = analysis.df" - ] - }, - { - "cell_type": "markdown", - "id": "c9f1411e", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Completeness of peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "%time not_missing = vaep.data_handling.get_sorted_not_missing(X)\n", - "not_missing.iloc[:, -10:].describe()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d83e6998", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "sample_completeness = not_missing.sum(axis=1).sort_values() / X.shape[-1]\n", - "sample_completeness" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b70f867c", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "N_MOST_COMMON_PEPTIDES = 300\n", - "data_to_visualize = not_missing.iloc[:, -N_MOST_COMMON_PEPTIDES:]\n", - "data_to_visualize = data_to_visualize.loc[sample_completeness.index]\n", - "print(f\"Look at missingness pattern of {N_MOST_COMMON_PEPTIDES} most common peptides across sample.\\n\"\n", - " f\"Data matrix dimension used for printing: { data_to_visualize.shape}\")\n", - "\n", - "\n", - "fig_heatmap_missing, axes_heatmap_missing = plt.subplots(\n", - " 1, 1, figsize=(12, 8))\n", - "USE_CBAR = False\n", - "\n", - "axes_heatmap_missing = sns.heatmap(data_to_visualize,\n", - " ax=axes_heatmap_missing,\n", - " cbar=USE_CBAR,\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "White patches indicates that a peptide has been measured, black means it was not measured. Some samples (rows) have few of the most common peptides. This suggests to set a minimum of total peptides in a sample, which is common pratice.\n", - "\n", - "> An algorithm should work with the most common peptides and base it's inference capabilities after training on these." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_to_visualize.sum(axis=1).nsmallest(20) # Samplest with the fewest measurements out of the seletion" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "# # This currently crashes if you want to have a pdf\n", - "datetime_now = datetime.now()\n", - "_savefig = partial(_savefig, folder=FIGUREFOLDER)\n", - "\n", - "_savefig(fig_heatmap_missing,\n", - " f'peptides_heatmap_missing_{datetime_now:%y%m%d}', pdf=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Sample stats" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "TYPE = 'peptides'\n", - "COL_NO_MISSING, COL_NO_IDENTIFIED = f'no_missing_{TYPE}', f'no_identified_{TYPE}'\n", - "COL_PROP_SAMPLES = 'prop_samples'\n", - "\n", - "\n", - "sample_stats = vaep.data_handling.compute_stats_missing(not_missing, COL_NO_MISSING, COL_NO_IDENTIFIED)\n", - "sample_stats" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "fig_ident = sns.relplot(\n", - " x='SampleID_int', y=COL_NO_IDENTIFIED, data=sample_stats)\n", - "fig_ident.set_axis_labels('Sample ID', f'Frequency of identified {TYPE}')\n", - "fig_ident.fig.suptitle(f'Frequency of identified {TYPE} by sample id', y=1.03)\n", - "_savefig(fig_ident, f'identified_{TYPE}_by_sample', folder=FIGUREFOLDER)\n", - "\n", - "fig_ident_dist = sns.relplot(\n", - " x=COL_PROP_SAMPLES, y=COL_NO_IDENTIFIED, data=sample_stats)\n", - "fig_ident_dist.set_axis_labels(\n", - " 'Proportion of samples (sorted by frequency)', f'Frequency of identified {TYPE}')\n", - "fig_ident_dist.fig.suptitle(\n", - " f'Frequency of identified {TYPE} groups by sample id', y=1.03)\n", - "_savefig(fig_ident_dist, f'identified_{TYPE}_ordered', folder=FIGUREFOLDER)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "COL_NO_MISSING_PROP = COL_NO_MISSING + '_PROP'\n", - "sample_stats[COL_NO_MISSING_PROP] = sample_stats[COL_NO_MISSING] / \\\n", - " float(X.shape[1])\n", - "\n", - "# from ggplot import *\n", - "# ggplot(aes(x='nan_proc'), data = nonnan) + geom_histogram(binwidth = 0.005) #+ ylim(0,0.025)\n", - "sns.set(style=\"darkgrid\")\n", - "g = sns.relplot(x='prop_samples', y=COL_NO_MISSING_PROP, data=sample_stats)\n", - "plt.subplots_adjust(top=0.9)\n", - "g.set_axis_labels(\n", - " \"Proportion of samples (sorted by frequency)\", \"proportion missing\")\n", - "g.fig.suptitle(f'Proportion of missing {TYPE} ordered')\n", - "_savefig(g, \"proportion_proteins_missing\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Look at sequences\n", - "\n", - "Shows mainly that from a 6-7 AA on, peptides sequences are nearly unique.\n", - "\n", - "> Overlapping peptides (from the start or the end) could still be interesting to find" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "class SequenceAnalyser():\n", - "\n", - " def __init__(self, sequences: pd.Series):\n", - " if not isinstance(sequences, pd.Series):\n", - " raise ValueError(\n", - " \"Please provide a pandas.Series, not {}\".format(type(sequences)))\n", - " self.sequences = sequences\n", - "\n", - " def calc_counts(self, n_characters):\n", - " return self.sequences.str[:n_characters].value_counts()\n", - "\n", - " def length(self):\n", - " return self.sequences.str.len().sort_values()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "sequences = SequenceAnalyser(X.columns.to_series())\n", - "sequences.length()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b7979950", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "_ = w.interact(sequences.calc_counts,\n", - " n_characters=w.IntSlider(value=4, min=1, max=55))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "431b9221", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "sequences_p4 = sequences.calc_counts(4)\n", - "display(sequences_p4.head())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a00e631b", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "sequences_p4.loc[sequences_p4.isin(('CON_', 'REV_'))].sort_index()" - ] - }, - { - "cell_type": "markdown", - "id": "0bc4e272", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "What to do when\n", - "\n", - "\n", - "```\n", - "AAAAAAAAAAGAAGGRGSGPGR\n", - "AAAAAAAAAAGAAGGRGSGPGRR\n", - "\n", - "AAAANSGSSLPLFDCPTWAGKPPPGLHLDVVK\n", - "AAAANSGSSLPLFDCPTWAGKPPPGLHLDVVKGDK\n", - "```\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "id": "821af58a", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Select Training Data" - ] - }, - { - "cell_type": "markdown", - "id": "e83f0238", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Minumum required sample quality\n", - "First define the minum requirement of a sample to be kept in" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b2517983", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "range_peps = (0, max(sample_stats[COL_NO_IDENTIFIED]))\n", - "MIN_DEPTH_SAMPLE = int(range_peps[1] * 0.6)\n", - "w_min_depth_sample = w.IntSlider(\n", - " value=MIN_DEPTH_SAMPLE, min=0, max=range_peps[1])\n", - "print(f'Minimum {TYPE} per sample observed:')\n", - "w_min_depth_sample" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d4b59bd2", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "mask_samples = sample_stats[COL_NO_IDENTIFIED] >= w_min_depth_sample.value\n", - "print(f\"Selected {mask_samples.sum()} samples\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e75668aa", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "x_50 = coverage(X.loc[mask_samples], coverage_col=0.5, coverage_row=0.2)\n", - "# x_50_pca = log_z_zeroone_na(x_50) # there is a huge difference if NA is set to low value or mean!!\n", - "x_90 = coverage(X.loc[mask_samples], 0.9, 0.9)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1e3135a6", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "x_50.shape, x_90.shape" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f5be5099", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "x_90.sample()" - ] - }, - { - "cell_type": "markdown", - "id": "df2816dd", - "metadata": {}, - "source": [ - "Data selection should be done for each experiment, so it is not resaved here" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "864cc51c", - "metadata": {}, - "outputs": [], - "source": [ - "#from vaep.io.data_objects import get_fname\n", - "# fname = config.FOLDER_DATA / get_fname(*x_90.shape)\n", - "# print(fname)\n", - "# x_90.to_csv(fname)\n", - "# fname = config.FOLDER_DATA / get_fname(*x_50.shape)\n", - "# print(fname)\n", - "# x_50.to_csv(fname)" - ] - }, - { - "cell_type": "markdown", - "id": "3d8ea98b", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Distribution of Intensity values\n", - "- comparing non-transformed to $\\log_{10}$ transformed\n", - "- log transformation makes data more normal distributed\n", - "\n", - "> log10 or log2 or ln" - ] - }, - { - "cell_type": "markdown", - "id": "6a9f9f88", - "metadata": {}, - "source": [ - "#### Sample with all peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cd813441", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "sample = x_50.sample().iloc[0]\n", - "sample_id = sample.name\n", - "print(\"Sample ID:\", sample_id)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "83097013", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "\n", - "sns.set(style=\"darkgrid\")\n", - "\n", - "\n", - "def plot_dist_comparison(\n", - " sample: pd.Series, figsize=(12, 5),\n", - " log=np.log, log_name=None,\n", - ") -> matplotlib.figure.Figure:\n", - " fig, axes = plt.subplots(1, 2, figsize=figsize)\n", - "\n", - " sns.histplot(sample, bins=100, ax=axes[0])\n", - " axes[0].set_title(\"Unnormalized distribution\")\n", - "\n", - " sample_log = log(sample)\n", - " sns.histplot(sample_log, bins=100, ax=axes[1])\n", - " if not log_name:\n", - " log_name = str(log).split(\"'\")[1]\n", - " axes[1].set_title(f\"{log_name} normalized distribution\")\n", - " sample_id = sample.name\n", - " _ = fig.suptitle(f\"Dynamic Range of measured intensities in sample {sample_id}\")\n", - " fig.tight_layout(rect=[0, 0.03, 1, 0.95])\n", - " return fig\n", - "\n", - "\n", - "fig = plot_dist_comparison(sample)\n", - "_savefig(fig, f\"distribution_sample_peptides_{str(sample_id)}_ln\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cbcff3de", - "metadata": {}, - "outputs": [], - "source": [ - "fig = plot_dist_comparison(sample, log=np.log2)\n", - "_savefig(fig, f\"distribution_peptides_sample_{str(sample_id)}_log2\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "46fea6ba", - "metadata": {}, - "outputs": [], - "source": [ - "sample_log_stats = np.log2(sample).describe().to_frame('log2')\n", - "sample_log_stats['ln'] = np.log(sample).describe()\n", - "sample_log_stats" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6e1f2979", - "metadata": {}, - "outputs": [], - "source": [ - "print(f\"Factor for log2 to ln: {1 / np.log2(np.e) = :.3f}\")\n", - "c = 1 / np.log2(np.e)" - ] - }, - { - "cell_type": "markdown", - "id": "1de60bb5", - "metadata": {}, - "source": [ - "If $ log2(x) \\sim \\mathcal{N}\\big(\\mu_{log2}, \\sigma_{log2}^2 \\big) $, then $ ln(x) \\sim \\mathcal{N}\\big(0.693 \\cdot \\mu_{log2}, 0.693^2 \\cdot \\sigma_{log2}^2 \\big) $.\n", - "\n", - "> Question: Is a wider or narrower distribtion important, or does only be \"normal\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a233ca42", - "metadata": {}, - "outputs": [], - "source": [ - "print(f\"mean: {sample_log_stats.loc['mean','log2'] * c = : .3f}\")\n", - "print(f\"std : {sample_log_stats.loc['std' ,'log2'] * c = : .3f}\")" - ] - }, - { - "cell_type": "markdown", - "id": "fb999f0b", - "metadata": {}, - "source": [ - "#### One Peptide, all samples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "495cd93c", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "sample = x_50.sample(axis=1).squeeze()\n", - "peptide = sample.name\n", - "\n", - "fig = plot_dist_comparison(sample)\n", - "_savefig(fig, f\"distribution_peptide_samples_{str(peptide)}_ln\")" - ] - }, - { - "cell_type": "markdown", - "id": "56898125", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Reference table intensities (natural logarithm)\n", - "\n", - "14 to 23 spans a dynamic range of 3 orders of base 10" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8b08e367", - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "dynamic_range = pd.DataFrame(range(14, 24), columns=['x'])\n", - "dynamic_range['$e^x$'] = dynamic_range.x.apply(np.exp)\n", - "dynamic_range.set_index('x', inplace=True)\n", - "dynamic_range.index.name = ''\n", - "dynamic_range.T" - ] - }, - { - "cell_type": "markdown", - "id": "6d57a983", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Next UP" - ] - }, - { - "cell_type": "markdown", - "id": "0bc1af1f", - "metadata": {}, - "source": [] - }, - { - "cell_type": "markdown", - "id": "9a6a80d7", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Find Protein of Peptides\n", - "- check with some reference list of peptides: This is created in `project\\FASTA_tryptic_digest.ipynb`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7abf7a7f", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13" - }, - "nbdime-conflicts": { - "local_diff": [ - { - "diff": [ - { - "diff": [ - { - "diff": [ - { - "key": 4, - "op": "addrange", - "valuelist": "5" - }, - { - "key": 4, - "length": 1, - "op": "removerange" - } - ], - "key": 0, - "op": "patch" - } - ], - "key": "version", - "op": "patch" - } - ], - "key": "language_info", - "op": "patch" - } - ], - "remote_diff": [ - { - "diff": [ - { - "diff": [ - { - "key": 0, - "length": 1, - "op": "removerange" - } - ], - "key": "version", - "op": "patch" - } - ], - "key": "language_info", - "op": "patch" - } - ] - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/00_6_hela_training_data_exploration.py b/project/00_6_hela_training_data_exploration.py deleted file mode 100644 index 84cc616fc..000000000 --- a/project/00_6_hela_training_data_exploration.py +++ /dev/null @@ -1,418 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: vaep -# language: python -# name: vaep -# --- - -# %% [markdown] Collapsed="false" -# # Peptides -# -# Load peptides selected for training - -# %% Collapsed="false" -from datetime import datetime -from functools import partial -from pathlib import Path -from random import sample - -import ipywidgets as w -import numpy as np -import pandas as pd -import matplotlib -import matplotlib.pyplot as plt - -# from sklearn import preprocessing -# from sklearn.decomposition import PCA -import seaborn as sns - -import vaep -from vaep.data_handling import coverage -from vaep.plotting import _savefig - -import config -from vaep.analyzers import analyzers -from vaep.io.data_objects import PeptideCounter -from vaep.transform import log - -pd.options.display.max_columns = 100 -pd.options.display.min_rows = 30 - -# %% [markdown] -# ## Descriptive Statistics (Linear case) -# -# - spread of peptide quantifications between samples -# - spread of quantifications within samples -# - correlation analysis: can linear correlation be picked up? -# - -# %% [markdown] -# ### Peptides - -# %% -FN_PEPTIDE_INTENSITIES = Path( - 'data/dev_datasets/df_intensities_proteinGroups_long_2017_2018_2019_2020_N05015_M04547/Q_Exactive_HF_X_Orbitrap_Exactive_Series_slot_#6070.csv') -FIGUREFOLDER = FN_PEPTIDE_INTENSITIES.parent / 'figures' / FN_PEPTIDE_INTENSITIES.stem -FIGUREFOLDER.mkdir(exist_ok=True, parents=True) -FIGUREFOLDER - -# %% -N_FIRST_ROWS = None # possibility to select N first rows -analysis = analyzers.AnalyzePeptides.from_csv(fname=FN_PEPTIDE_INTENSITIES, index_col=[0, 1], nrows=N_FIRST_ROWS) -df = analysis.to_wide_format() -analysis.describe_peptides(sample_n=30) - -# %% [markdown] -# ### Peptide frequency: sellect the N most common peptides -# -# - N most common peptides between samples - -# %% -N = 10 - -peptide_counter = PeptideCounter(config.FNAME_C_PEPTIDES) -peptide_counter.counter.most_common(N) - -# %% -counts = analysis.df.count().sort_values(ascending=False) -counts.iloc[:N] - -# %% -analysis.df[counts.iloc[:N].index] - -# %% [markdown] -# ## Correlation between peptides -# - linear correlation as indicator that there is some variation which could be used by models (or other heuristics) - -# %% -sample = analysis.df.sample(n=30, axis=1) -# ToDo func is assigned to df -corr_lower_triangle = analyzers.corr_lower_triangle(sample) -corr_lower_triangle - -# %% -fig, axes = analyzers.plot_corr_histogram(corr_lower_triangle, bins=40) - -# %% [markdown] -# ### Samples - -# %% -analysis.df.sample(30, axis=0).T.describe() - -# %% [markdown] -# ### Peptides (all) - -# %% -stats = analysis.describe_peptides() - -# %% -# biological coefficient of variation: standard deviation (variation) w.r.t mean -_ = stats.loc['CV'].hist(figsize=(10, 4)) - -# %% -_ = stats.loc['count'].hist(figsize=(10, 4)) - -# %% Collapsed="false" -INDEX_NAME = 'Sample ID' -analysis.df.index.name = INDEX_NAME - -# %% Collapsed="false" -analysis.df - -# %% Collapsed="false" -N_MIN_OBS = analysis.df.shape[0] * 0.7 # here: present in 70% of the samples -mask_min_obsevation = analysis.df.notna().sum() >= N_MIN_OBS -mask_min_obsevation.sum() - -# %% [markdown] -# Reference analysis.df as `X` - -# %% -X = analysis.df - -# %% [markdown] Collapsed="false" -# ## Completeness of peptides - -# %% Collapsed="false" -# %time not_missing = vaep.data_handling.get_sorted_not_missing(X) -not_missing.iloc[:, -10:].describe() - -# %% Collapsed="false" -sample_completeness = not_missing.sum(axis=1).sort_values() / X.shape[-1] -sample_completeness - -# %% Collapsed="false" -N_MOST_COMMON_PEPTIDES = 300 -data_to_visualize = not_missing.iloc[:, -N_MOST_COMMON_PEPTIDES:] -data_to_visualize = data_to_visualize.loc[sample_completeness.index] -print(f"Look at missingness pattern of {N_MOST_COMMON_PEPTIDES} most common peptides across sample.\n" - f"Data matrix dimension used for printing: { data_to_visualize.shape}") - - -fig_heatmap_missing, axes_heatmap_missing = plt.subplots( - 1, 1, figsize=(12, 8)) -USE_CBAR = False - -axes_heatmap_missing = sns.heatmap(data_to_visualize, - ax=axes_heatmap_missing, - cbar=USE_CBAR, - ) - -# %% [markdown] -# White patches indicates that a peptide has been measured, black means it was not measured. Some samples (rows) have few of the most common peptides. This suggests to set a minimum of total peptides in a sample, which is common pratice. -# -# > An algorithm should work with the most common peptides and base it's inference capabilities after training on these. - -# %% -data_to_visualize.sum(axis=1).nsmallest(20) # Samplest with the fewest measurements out of the seletion - -# %% Collapsed="false" -# # This currently crashes if you want to have a pdf -datetime_now = datetime.now() -_savefig = partial(_savefig, folder=FIGUREFOLDER) - -_savefig(fig_heatmap_missing, - f'peptides_heatmap_missing_{datetime_now:%y%m%d}', pdf=False) - -# %% [markdown] Collapsed="false" -# ## Sample stats - -# %% Collapsed="false" -TYPE = 'peptides' -COL_NO_MISSING, COL_NO_IDENTIFIED = f'no_missing_{TYPE}', f'no_identified_{TYPE}' -COL_PROP_SAMPLES = 'prop_samples' - - -sample_stats = vaep.data_handling.compute_stats_missing(not_missing, COL_NO_MISSING, COL_NO_IDENTIFIED) -sample_stats - -# %% Collapsed="false" -fig_ident = sns.relplot( - x='SampleID_int', y=COL_NO_IDENTIFIED, data=sample_stats) -fig_ident.set_axis_labels('Sample ID', f'Frequency of identified {TYPE}') -fig_ident.fig.suptitle(f'Frequency of identified {TYPE} by sample id', y=1.03) -_savefig(fig_ident, f'identified_{TYPE}_by_sample', folder=FIGUREFOLDER) - -fig_ident_dist = sns.relplot( - x=COL_PROP_SAMPLES, y=COL_NO_IDENTIFIED, data=sample_stats) -fig_ident_dist.set_axis_labels( - 'Proportion of samples (sorted by frequency)', f'Frequency of identified {TYPE}') -fig_ident_dist.fig.suptitle( - f'Frequency of identified {TYPE} groups by sample id', y=1.03) -_savefig(fig_ident_dist, f'identified_{TYPE}_ordered', folder=FIGUREFOLDER) - -# %% Collapsed="false" -COL_NO_MISSING_PROP = COL_NO_MISSING + '_PROP' -sample_stats[COL_NO_MISSING_PROP] = sample_stats[COL_NO_MISSING] / \ - float(X.shape[1]) - -# from ggplot import * -# ggplot(aes(x='nan_proc'), data = nonnan) + geom_histogram(binwidth = 0.005) #+ ylim(0,0.025) -sns.set(style="darkgrid") -g = sns.relplot(x='prop_samples', y=COL_NO_MISSING_PROP, data=sample_stats) -plt.subplots_adjust(top=0.9) -g.set_axis_labels( - "Proportion of samples (sorted by frequency)", "proportion missing") -g.fig.suptitle(f'Proportion of missing {TYPE} ordered') -_savefig(g, "proportion_proteins_missing") - - -# %% [markdown] Collapsed="false" -# ## Look at sequences -# -# Shows mainly that from a 6-7 AA on, peptides sequences are nearly unique. -# -# > Overlapping peptides (from the start or the end) could still be interesting to find - -# %% Collapsed="false" -class SequenceAnalyser(): - - def __init__(self, sequences: pd.Series): - if not isinstance(sequences, pd.Series): - raise ValueError( - "Please provide a pandas.Series, not {}".format(type(sequences))) - self.sequences = sequences - - def calc_counts(self, n_characters): - return self.sequences.str[:n_characters].value_counts() - - def length(self): - return self.sequences.str.len().sort_values() - - -# %% Collapsed="false" -sequences = SequenceAnalyser(X.columns.to_series()) -sequences.length() - -# %% Collapsed="false" -_ = w.interact(sequences.calc_counts, - n_characters=w.IntSlider(value=4, min=1, max=55)) - -# %% Collapsed="false" -sequences_p4 = sequences.calc_counts(4) -display(sequences_p4.head()) - -# %% Collapsed="false" -sequences_p4.loc[sequences_p4.isin(('CON_', 'REV_'))].sort_index() - -# %% [markdown] Collapsed="false" -# What to do when -# -# -# ``` -# AAAAAAAAAAGAAGGRGSGPGR -# AAAAAAAAAAGAAGGRGSGPGRR -# -# AAAANSGSSLPLFDCPTWAGKPPPGLHLDVVK -# AAAANSGSSLPLFDCPTWAGKPPPGLHLDVVKGDK -# ``` -# -# - -# %% [markdown] Collapsed="false" -# ## Select Training Data - -# %% [markdown] Collapsed="false" -# ### Minumum required sample quality -# First define the minum requirement of a sample to be kept in - -# %% Collapsed="false" -range_peps = (0, max(sample_stats[COL_NO_IDENTIFIED])) -MIN_DEPTH_SAMPLE = int(range_peps[1] * 0.6) -w_min_depth_sample = w.IntSlider( - value=MIN_DEPTH_SAMPLE, min=0, max=range_peps[1]) -print(f'Minimum {TYPE} per sample observed:') -w_min_depth_sample - -# %% Collapsed="false" -mask_samples = sample_stats[COL_NO_IDENTIFIED] >= w_min_depth_sample.value -print(f"Selected {mask_samples.sum()} samples") - -# %% Collapsed="false" -x_50 = coverage(X.loc[mask_samples], coverage_col=0.5, coverage_row=0.2) -# x_50_pca = log_z_zeroone_na(x_50) # there is a huge difference if NA is set to low value or mean!! -x_90 = coverage(X.loc[mask_samples], 0.9, 0.9) - -# %% Collapsed="false" -x_50.shape, x_90.shape - -# %% Collapsed="false" -x_90.sample() - -# %% [markdown] -# Data selection should be done for each experiment, so it is not resaved here - -# %% -#from vaep.io.data_objects import get_fname -# fname = config.FOLDER_DATA / get_fname(*x_90.shape) -# print(fname) -# x_90.to_csv(fname) -# fname = config.FOLDER_DATA / get_fname(*x_50.shape) -# print(fname) -# x_50.to_csv(fname) - -# %% [markdown] Collapsed="false" -# ### Distribution of Intensity values -# - comparing non-transformed to $\log_{10}$ transformed -# - log transformation makes data more normal distributed -# -# > log10 or log2 or ln - -# %% [markdown] -# #### Sample with all peptides - -# %% Collapsed="false" -sample = x_50.sample().iloc[0] -sample_id = sample.name -print("Sample ID:", sample_id) - -# %% Collapsed="false" - -sns.set(style="darkgrid") - - -def plot_dist_comparison( - sample: pd.Series, figsize=(12, 5), - log=np.log, log_name=None, -) -> matplotlib.figure.Figure: - fig, axes = plt.subplots(1, 2, figsize=figsize) - - sns.histplot(sample, bins=100, ax=axes[0]) - axes[0].set_title("Unnormalized distribution") - - sample_log = log(sample) - sns.histplot(sample_log, bins=100, ax=axes[1]) - if not log_name: - log_name = str(log).split("'")[1] - axes[1].set_title(f"{log_name} normalized distribution") - sample_id = sample.name - _ = fig.suptitle(f"Dynamic Range of measured intensities in sample {sample_id}") - fig.tight_layout(rect=[0, 0.03, 1, 0.95]) - return fig - - -fig = plot_dist_comparison(sample) -_savefig(fig, f"distribution_sample_peptides_{str(sample_id)}_ln") - -# %% -fig = plot_dist_comparison(sample, log=np.log2) -_savefig(fig, f"distribution_peptides_sample_{str(sample_id)}_log2") - -# %% -sample_log_stats = np.log2(sample).describe().to_frame('log2') -sample_log_stats['ln'] = np.log(sample).describe() -sample_log_stats - -# %% -print(f"Factor for log2 to ln: {1 / np.log2(np.e) = :.3f}") -c = 1 / np.log2(np.e) - -# %% [markdown] -# If $ log2(x) \sim \mathcal{N}\big(\mu_{log2}, \sigma_{log2}^2 \big) $, then $ ln(x) \sim \mathcal{N}\big(0.693 \cdot \mu_{log2}, 0.693^2 \cdot \sigma_{log2}^2 \big) $. -# -# > Question: Is a wider or narrower distribtion important, or does only be "normal" - -# %% -print(f"mean: {sample_log_stats.loc['mean','log2'] * c = : .3f}") -print(f"std : {sample_log_stats.loc['std' ,'log2'] * c = : .3f}") - -# %% [markdown] -# #### One Peptide, all samples - -# %% Collapsed="false" -sample = x_50.sample(axis=1).squeeze() -peptide = sample.name - -fig = plot_dist_comparison(sample) -_savefig(fig, f"distribution_peptide_samples_{str(peptide)}_ln") - -# %% [markdown] Collapsed="false" -# ### Reference table intensities (natural logarithm) -# -# 14 to 23 spans a dynamic range of 3 orders of base 10 - -# %% Collapsed="false" -dynamic_range = pd.DataFrame(range(14, 24), columns=['x']) -dynamic_range['$e^x$'] = dynamic_range.x.apply(np.exp) -dynamic_range.set_index('x', inplace=True) -dynamic_range.index.name = '' -dynamic_range.T - -# %% [markdown] Collapsed="false" -# ## Next UP - -# %% [markdown] -# - -# %% [markdown] Collapsed="false" -# ### Find Protein of Peptides -# - check with some reference list of peptides: This is created in `project\FASTA_tryptic_digest.ipynb` - -# %% diff --git a/project/README.md b/project/README.md index 95f54336d..8091caa67 100644 --- a/project/README.md +++ b/project/README.md @@ -70,8 +70,6 @@ papermill 01_0_split_data.ipynb runs/experiment_03/%DATASET%/experiment_03_data ## Notebooks -- erda: Is the longterm storage of the university -> MQ output was processed on a server attached to erda -- hela: dumps from erda processing (raw file names, aggregated `summaries.txt` from MQ, protein groups, peptides and precursor dumps) - run: a single experiment with models attached, see `workflow/Snakefile` - grid: only grid search associated, see `workflow/Snakefile_grid.smk` - best: best models repeatedly trained or across datasets, see `workflow/Snakefile_best_repeated_train.smk` and `workflow/Snakefile_best_across_datasets.smk` @@ -79,21 +77,6 @@ papermill 01_0_split_data.ipynb runs/experiment_03/%DATASET%/experiment_03_data tag | notebook | Description --- | --- | --- -Development data related -erda | erda_01_mq_select_runs.ipynb | Aggregate current summary files from MQ runs into table -erda | erda_02_mq_count_features.ipynb | Aggregate information from all eligable MQ runs
Saves processed files used for data selection (Counters used in `erda_03_training_data.ipynb`) -erda | erda_03_training_data.ipynb | Build training data dump (run for each data level) in wide format -erda | erda_04_transpose_data.ipynb | Transpose dataset (row: a sample), separate as erda has memory limits, dump counts and present-absent patterns -erda | erda_12_explore_raw_MQ_data.ipynb | Load a single MQ txt output folder and browse data
dumps large pickle files for training -erda | erda_data_available.ipynb | Plots on theoretically available data based on Counter dictionaries -hela | 00_0_hela_metadata_rawfiles.ipynb | Analyze rawfile metadata and prepare for data selection -hela | 00_1_hela_MQ_summaries.ipynb | Analyzse summaries.txt data from all samples -hela | 00_2_hela_all_raw_files.ipynb | Find duplicate raw files, analyze sizes -hela | 00_3_hela_selected_files_overview.ipynb | Data description based on file size and metaddata of selected files -hela | 00_4_hela_development_dataset_splitting | Splitting data into development datasets of HeLa cell line data (based on wide format input from `erda_03` and `erda_04`) -Single development dataset | -hela | 00_5_hela_development_dataset_support.ipynb | Support of training data samples/feat on selected development data set -hela | 00_6_hela_training_data_exploration.ipynb | Explore a data set for diagnositics
Visualize key metrics Single experiment | run | 01_0_split_data.ipynb | Create train, validation and test data splits run | 01_1_train_.ipynb | Train a single model e.g. (VAE, DAE, CF) @@ -111,13 +94,7 @@ ald | 16_ald_compare_methods.ipynb | DA comparison between methods ald | 16_ald_ml_new_feat.ipynb | ML model comparison ald | 16_ald_compare_single_pg.ipynb | [DEV] Compare imputation for feat between methods (dist plots) Miscancellous notebooks on different topics (partly exploration) | -misc | misc_clustering_proteins.ipynb | \[documentation\] PCA protein analysis from Annelaura w/ initial data
(Executed, only for documentation) -misc | misc_data_exploration_peptides.ipynb | Describe current peptides training data -misc | misc_data_exploration_proteins.ipynb | \[NEEDS UPDATE\] Describe small initial protein training data misc | misc_embeddings.ipynb | FastAI Embeddings -misc | misc_FASTA_data_agg_by_gene.ipynb | Investigate possibility to join proteins by gene -misc | misc_FASTA_tryptic_digest.ipynb | Analyze fasta file used for peptide identification -misc | misc_id_mapper.ipynb | train models per gene, see overlaps in proteins, see coverage | of proteins with observed peptides, align overlapping peptide sequences misc | misc_illustrations.ipynb | Illustrations of certain concepts (e.g. draw from shifted random distribution) misc | misc_json_formats.ipynb | Investigate storring training data as json with correct encoding misc | misc_MaxQuantOutput.ipynb | \[documentation\] Analyze MQ output, show MaxQuantOutput class behaviour @@ -128,74 +105,6 @@ misc | misc_sampling_in_pandas.ipynb | How to sample in pandas # Notebook descriptions (To be completed) -## erda notebooks - -- [ ] determine order and rename accordingly with prefix - -The data is for now processed only using MaxQuant. If the files are processed -by another Software, these notebooks need to be adapted for if they contain `mq` or `MQ`. - -### erda_01_mq_select_runs - -- read in all summaries and select eligable runs based on number of identified peptides - -### erda_02_mq_count_features - -- Feature Extraction and Feature counting -- dumps extracted features per group into `FOLDER_PROCESSED` - (separated for type and by year) - -### erda_03_training_data - -- needs to be executed for each data type -- loads a python config file (setting `FeatureCounter` classes and custom functions) - along string configuration variables - -## HeLa notebooks - Training data - - -### `00_0_1_rawfile_renaming.ipynb` - -> internal, documentation only (see pride upload for result) - -- create a new id for each raw file based on the creation date and instrument -- uses metadata -- build lftp commands for pride upload - -### `00_0_hela_metadata_rawfiles.ipynb` - -- group by MS instrument parameters -- create `data/files_per_instrument_nested.yaml` for selection of data by massspectrometer - -### `00_1_hela_MQ_summaries.ipynb` - -- analysze all `summaries.txt` - -### `00_2_hela_all_raw_files.ipynb` - -### `00_3_hela_selected_files_overview.ipynb` - -- created joined metadata file -- overview of metadata of selected files for data descriptor paper - -### `00_4_hela_development_dataset_splitting.ipynb` - -- Create development dataset(s) of common machines, one for each machine -- UMAP **Figure 1b**, statistics of **Figure 1c** -- create datasets for training PIMMS models - -### Training data inspection - -### `00_5_hela_development_dataset_support.ipynb` - -- feature counts for a single development dataset (e.g. for a single machine) - -### `00_6_hela_training_data_exploration.ipynb` - -> needs clean-up - -- explore a data set for diagnositics - ## Single experiment run ### `01_0_split_data.ipynb` diff --git a/project/config/__init__.py b/project/config/__init__.py deleted file mode 100644 index af7a2d97b..000000000 --- a/project/config/__init__.py +++ /dev/null @@ -1,226 +0,0 @@ -# src.config goes here -# import src.config -> import config - -""" -Project config file. - -Different config for different settings. - -os to pathlib functionaly, see -https://docs.python.org/3/library/pathlib.html#correspondence-to-tools-in-the-os-module - -""" -import vaep.io -import logging -import yaml -from collections import namedtuple -from pathlib import Path, PurePath, PurePosixPath -from pprint import pformat - -import numpy as np -import pandas -import matplotlib as mpl - - -def mkdir(path=Path): - path.mkdir(exist_ok=True, parents=True) - return path - - -logger = logging.getLogger('vaep') - -############################################################################### -############################################################################### -# project folder specific -FIGUREFOLDER = Path('Figures') -FIGUREFOLDER.mkdir(exist_ok=True) - -FOLDER_DATA = Path('data') -FOLDER_DATA.mkdir(exist_ok=True) - -FOLDER_PROCESSED = FOLDER_DATA / 'processed' -FOLDER_PROCESSED.mkdir(exist_ok=True) - -FOLDER_TRAINING = mkdir(FOLDER_DATA / 'hela_qc_data') - -# (old) Synonyms -PROCESSED_DATA = FOLDER_PROCESSED -PROTEIN_DUMPS = PROCESSED_DATA - -############################################################################### -############################################################################### -# Adapt this part -ON_ERDA = True -#local PC config -FOLDER_MQ_TXT_DATA = None - -FOLDERS_MQ_TXT_DATA = [ - Path('Y:/') / 'mq_out', - FOLDER_DATA / 'mq_out', - Path('/home/jovyan/work/mq_out/'), -] -for folder in FOLDERS_MQ_TXT_DATA[:-1]: - if folder.exists(): - print(f'FOLDER_MQ_TXT_DATA = {folder}') - FOLDER_MQ_TXT_DATA = folder - ON_ERDA = False - break - -if FOLDERS_MQ_TXT_DATA[-1].exists(): - print(f'FOLDER_MQ_TXT_DATA = {folder}') - FOLDER_MQ_TXT_DATA = folder - -if not FOLDER_MQ_TXT_DATA: - print( - 'Not found. Check FOLDER_MQ_TXT_DATA entries above: {}'.format( - ", ".join([str(fname) for fname in FOLDERS_MQ_TXT_DATA]) - ) - ) - FOLDER_MQ_TXT_DATA = FOLDERS_MQ_TXT_DATA[1] - FOLDER_MQ_TXT_DATA.mkdir() - ON_ERDA = False - print(f"Created local folder: {FOLDER_MQ_TXT_DATA}") - -if ON_ERDA: - import sys - sys.path.append('/home/jovyan/work/vaep/') - - FOLDER_MQ_TXT_DATA = Path('/home/jovyan/work/mq_out/') - if FOLDER_MQ_TXT_DATA.exists(): - print(f'FOLDER_MQ_TXT_DATA = {FOLDER_MQ_TXT_DATA}') - else: - raise FileNotFoundError(f"Check config for FOLDER_MQ_TXT_DATA") - - FOLDER_RAW_DATA = Path('/home/jovyan/work/share_hela_raw/') - if FOLDER_RAW_DATA.exists(): - print(f'FOLDER_RAW_DATA = {FOLDER_RAW_DATA}') - else: - raise FileNotFoundError( - f"Check config for FOLDER_RAW_DATA: {FOLDER_RAW_DATA}") - -# FOLDER_KEY = None - -FOLDER_KEY = 'txt' - -############################################################################### -############################################################################### -# Files - -FN_ALL_SUMMARIES = FOLDER_PROCESSED / 'all_summaries.json' - -#FN_PEPTIDE_INTENSITIES = Path(FOLDER_DATA) / 'mq_out' / 'peptide_intensities.pkl' -FN_PEPTIDE_STUMP = 'peptide_intensities' -FN_PEPTIDE_INTENSITIES = Path(FOLDER_DATA) / 'peptide_intensities.pkl' - -FN_PROTEIN_TSV = FOLDER_DATA / 'Mann_Hepa_data.tsv' - -PREFIX_IMPUTED = 'hela_imputed_proteins' -PREFIX_META = 'hela_metadata' - -FOLDER_FASTA = Path(FOLDER_DATA) / 'fasta' -FN_FASTA_DB = FOLDER_FASTA / 'fasta_db.json' -FN_ID_MAP = FOLDER_FASTA / 'id_map.json' -FN_PROT_GENE_MAP = FOLDER_FASTA / 'uniprot_protein_gene_map.json' -FN_PEP_TO_PROT = FOLDER_FASTA / 'peptided_to_prot_id.json' -FN_PROTEIN_SUPPORT_MAP = Path(FOLDER_DATA) / 'protein_support.pkl' -FN_PROTEIN_SUPPORT_FREQ = Path(FOLDER_DATA) / 'dict_protein_support_freq.pkl' - -FN_ALL_RAW_FILES = 'all_raw_files_dump.txt' - -# DATA FASTA Config -KEY_FASTA_HEADER = 'meta' -KEY_FASTA_SEQ = 'seq' -KEY_PEPTIDES = 'peptides' -KEY_GENE_NAME = 'gene' -KEY_GENE_NAME_FASTA = 'gene_fasta' - -KEYS_FASTA_ENTRY = [KEY_FASTA_HEADER, - KEY_FASTA_SEQ, KEY_PEPTIDES, KEY_GENE_NAME] - -FastaEntry = namedtuple('FastaEntry', KEYS_FASTA_ENTRY) -fasta_entry = FastaEntry(*KEYS_FASTA_ENTRY) - - -FILEPATH_UTILS = 'src/file_utils.py' - -FNAME_C_PEPTIDES = FOLDER_PROCESSED / \ - 'count_all_peptides.json' # aggregated peptides -# evidence peptides (sequence, charge, modification) -FNAME_C_EVIDENCE = FOLDER_PROCESSED / 'count_all_evidences.json' - -FNAME_C_PG = FOLDER_PROCESSED / 'count_all_protein_groups.json' -FNAME_C_GENES = FOLDER_PROCESSED / 'count_all_genes.json' - - -def build_df_fname(df: pandas.DataFrame, stub: str) -> str: - N, M = df.shape - return f'{stub}_N{N:05d}_M{M:05d}' - - -def insert_shape(df: pandas.DataFrame, template: str = "filename{}.txt", shape=None): - if shape is None: - N, M = df.shape - else: - N, M = shape - return template.format(f'_N{N:05d}_M{M:05d}') - -# put to testing -# df_test = pd.DataFrame(np.random.randint(low=-4, high=10, size=(1729, 146))) -# N, M = df_test.shape -# assert build_fname(df=df_test, stub='df_intensities') == f'df_intensities_N{N:05d}_M{M:05d}' - - -############################################################################### -############################################################################### -# configure plotting -# https://matplotlib.org/stable/users/dflt_style_changes.html -mpl.rcParams['figure.figsize'] = [10.0, 8.0] - -# cfg.keys.gene_name -# cfg.paths.processed -# cfg. - - -class Config(): - """Config class with a setter enforcing that config entries cannot - be overwritten. - - - Can contain configs, which are itself configs: - keys, paths, - - """ - - def __setattr__(self, entry, value): - """Set if attribute not in instance.""" - if hasattr(self, entry) and getattr(self, entry) != value: - raise AttributeError( - f'{entry} already set to {getattr(self, entry)}') - super().__setattr__(entry, value) - - def __repr__(self): - return pformat(vars(self)) # does not work in Jupyter? - - def overwrite_entry(self, entry, value): - """Explicitly overwrite a given value.""" - super().__setattr__(entry, value) - - def dump(self, fname=None): - if fname is None: - try: - fname = self.out_folder - fname = Path(fname) / 'model_config.yml' - except AttributeError: - raise AttributeError( - 'Specify fname or set "out_folder" attribute.') - d = vaep.io.parse_dict(input_dict=self.__dict__) - with open(fname, 'w') as f: - yaml.dump(d, f) - logger.info(f"Dumped config to: {fname}") - - -if __name__ == '__main__': - cfg = Config() - cfg.test = 'test' - print(cfg.test) - cfg.test = 'raise ValueError' diff --git a/project/config/counter_fpaths.py b/project/config/counter_fpaths.py deleted file mode 100644 index 5d0218092..000000000 --- a/project/config/counter_fpaths.py +++ /dev/null @@ -1,7 +0,0 @@ -from .defaults import FOLDER_PROCESSED - -FNAME_C_PEPTIDES = FOLDER_PROCESSED / 'count_all_peptides.json' # aggregated peptides -FNAME_C_EVIDENCE = FOLDER_PROCESSED / 'count_all_evidences.json' # evidence peptides (sequence, charge, modification) - -FNAME_C_PG = FOLDER_PROCESSED / 'count_all_protein_groups.json' -FNAME_C_GENES = FOLDER_PROCESSED / 'count_all_genes.json' diff --git a/project/config/defaults.py b/project/config/defaults.py deleted file mode 100644 index 239453cb0..000000000 --- a/project/config/defaults.py +++ /dev/null @@ -1,17 +0,0 @@ -from pathlib import Path - - -def mkdir(path=Path): - path.mkdir(exist_ok=True, parents=True) - return path - - -# project folder specific -FIGUREFOLDER = mkdir(Path('Figures')) -FOLDER_DATA = mkdir(Path('data')) -FOLDER_PROCESSED = mkdir(FOLDER_DATA / 'processed') -FOLDER_TRAINING = mkdir(FOLDER_DATA / 'hela_qc_data') - -# (old) Synonyms -PROCESSED_DATA = FOLDER_PROCESSED -PROTEIN_DUMPS = PROCESSED_DATA \ No newline at end of file diff --git a/project/config/training_data/evidence.py b/project/config/training_data/evidence.py deleted file mode 100644 index e3651f867..000000000 --- a/project/config/training_data/evidence.py +++ /dev/null @@ -1,18 +0,0 @@ -from ..counter_fpaths import FNAME_C_EVIDENCE -from vaep.io import data_objects - -NAME = 'evidence' -BASE_NAME = f"df_intensities_{NAME}_long" - -TYPES_DUMP = {'Sample ID': 'category', - 'Sequence': 'category', - 'Charge': 'category',} - -TYPES_COUNT = {'Charge': int} - -IDX_COLS_LONG = ['Sample ID', 'Sequence', 'Charge'] # in order - -LOAD_DUMP = data_objects.load_evidence_dump - -CounterClass = data_objects.EvidenceCounter -FNAME_COUNTER = FNAME_C_EVIDENCE \ No newline at end of file diff --git a/project/config/training_data/peptides.py b/project/config/training_data/peptides.py deleted file mode 100644 index c4e8075a3..000000000 --- a/project/config/training_data/peptides.py +++ /dev/null @@ -1,19 +0,0 @@ -from ..counter_fpaths import FNAME_C_PEPTIDES -from vaep.io import data_objects - -NAME = 'peptides' -BASE_NAME = f"df_intensities_{NAME}_long" - -TYPES_DUMP = {'Sample ID': 'category', - 'Sequence': 'category', - } - -TYPES_COUNT = {} - -IDX_COLS_LONG = ['Sample ID', 'Sequence'] # in order - -LOAD_DUMP = data_objects.load_agg_peptide_dump - -CounterClass = data_objects.PeptideCounter -FNAME_COUNTER = FNAME_C_PEPTIDES - diff --git a/project/config/training_data/proteinGroups.py b/project/config/training_data/proteinGroups.py deleted file mode 100644 index 4158623cf..000000000 --- a/project/config/training_data/proteinGroups.py +++ /dev/null @@ -1,20 +0,0 @@ -from ..counter_fpaths import FNAME_C_GENES # use genes as identifier between samples -from vaep.io import data_objects - -NAME = 'proteinGroups' - -BASE_NAME = f"df_intensities_{NAME}_long" - -TYPES_DUMP = {'Sample ID': 'category', - 'Gene names': 'category', - } - -TYPES_COUNT = {} - -IDX_COLS_LONG = ['Sample ID', 'Gene names'] # in order - -LOAD_DUMP = data_objects.pg_idx_gene_fct - -CounterClass = data_objects.GeneCounter - -FNAME_COUNTER = FNAME_C_GENES diff --git a/project/erda_00_maxquant_file_reader.ipynb b/project/erda_00_maxquant_file_reader.ipynb deleted file mode 100644 index d4bcd42d9..000000000 --- a/project/erda_00_maxquant_file_reader.ipynb +++ /dev/null @@ -1,528 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "# MaxQuant (MQ) Output-Files\n", - "\n", - "Compare a single experiment\n", - "\n", - "Files compared:\n", - "1. `Summary.txt`\n", - "2. `mqpar.xml`\n", - "3. `peptides.txt`\n", - "4. `proteins.txt`\n", - "\n", - "There is are many files more, where several files seem to be available in several times in different formats." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import sys\n", - "import logging\n", - "from pathlib import Path\n", - "import random\n", - "from tqdm.notebook import tqdm\n", - "\n", - "import pandas as pd\n", - "import ipywidgets as widgets\n", - "\n", - "from vaep.io import PathsList\n", - "from vaep.io.mq import MaxQuantOutputDynamic\n", - "from vaep.io.mq import ExtractFromPeptidesTxt\n", - "import vaep.io.mq as mq\n", - "\n", - "\n", - "from src.file_utils import load_summary, load_mqpar_xml\n", - "from vaep.logging import setup_logger_w_file\n", - "\n", - "##################\n", - "##### CONFIG #####\n", - "##################\n", - "from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED\n", - "from config import FOLDER_KEY # defines how filenames are parsed for use as indices\n", - "\n", - "from config import FOLDER_DATA # project folder for storing the data\n", - "print(f\"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}\")\n", - "\n", - "##################\n", - "### Logging ######\n", - "##################\n", - "\n", - "# Delete Jupyter notebook root logger handler\n", - "root_logger = logging.getLogger()\n", - "root_logger.handlers = []\n", - "\n", - "logger = logging.getLogger('vaep')\n", - "logger = setup_logger_w_file(logger, fname_base='log_00_maxquant_file_reader')\n", - "\n", - "logger.info('Start with handlers: \\n' + \"\\n\".join(f\"- {repr(log_)}\" for log_ in logger.handlers))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir()]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "folders_dict = {folder.name: folder for folder in sorted(folders)}\n", - "assert len(folders_dict) == len(folders), \"Non unique file names\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "# w_file = widgets.Dropdown(options=[folder for folder in folders], description='View files')\n", - "w_file = widgets.Dropdown(options=folders_dict, description='View files')\n", - "w_file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output = MaxQuantOutputDynamic(w_file.value)\n", - "mq_output" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Results will be saved in a subfolder under `vaep/project/data` using the\n", - "name of the specified input-folder per default. Change to your liking:" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "> Go to the block you are interested in!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## MQ Summary files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.summary.iloc[0].to_dict()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### File Handler\n", - "\n", - "- dictionary of run name to run output folder\n", - "- find class with expected output folders" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "# load_summary??" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Summaries\n", - "\n", - "- aggregated in `vaep/project/erda_01_mq_aggregate_summaries.ipynb`\n", - " - file selection based on summaries for further analysis thereafter" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# paths_summaries = [str(folder / 'summary.txt') for folder in folders_dict.values()]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "# # if paths_summaries.files:\n", - "# if folders_dict:\n", - "# # df, names, failed = process_files(handler_fct=load_summary, filepaths=paths_summaries.files, key=FOLDER_KEY, relative_to='paths_summaries.folder')\n", - "# df, names, failed = process_files(handler_fct=load_summary, filepaths=paths_summaries, key=FOLDER_KEY, relative_to=None)\n", - "# df.columns = names\n", - "# print(f\"Number of failed reads: {len(failed)}\")\n", - "# display(df)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# # if paths_summaries.files:\n", - "# if paths_summaries:\n", - "# df.to_csv(os.path.join(FOLDER_PROCESSED, 'all_summary_txt.csv'))\n", - "# df.to_pickle(os.path.join(FOLDER_PROCESSED, 'all_summary_txt.pkl'))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- SIL - MS2 based on precursor which was a set of peaks\n", - "- PEAK - MS2 scan based on a single peak on precursor spectrum\n", - "- ISO - isotopic pattern detection\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# # if paths_summaries.files:\n", - "# if paths_summaries:\n", - "# MS_spectra = df.loc[['MS', 'MS/MS Identified']].T.astype('int64')\n", - "# mask = MS_spectra['MS/MS Identified'] > 0\n", - "# display(MS_spectra.loc[mask].describe())\n", - "# MS_spectra.to_csv(os.path.join(FOLDER_PROCESSED, 'overview_stats.csv'))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## MaxQuant Parameter File\n", - "\n", - "- partly in a separate subfolder\n", - "- mainly in run folders\n", - "- rebase on folders_dictionary (check for `.xml` files in all folders)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mqpar_files = (Path(FOLDER_DATA) / 'mqpar_files')\n", - "\n", - "mqpar_files = [file for file in mqpar_files.iterdir() if file.suffix == '.xml']\n", - "len(mqpar_files) # nested search needed" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "w_file = widgets.Dropdown(options=mqpar_files, description='Select a file')\n", - "w_file" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Parameter Files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "fname_mqpar_xml = os.path.join(FOLDER_PROCESSED, 'peptide_intensities.{}')\n", - "\n", - "d_mqpar = dict()\n", - "for file in tqdm(mqpar_files):\n", - " d_mqpar[file.stem] = load_mqpar_xml(file)['MaxQuantParams']\n", - "\n", - "df_mqpar = pd.DataFrame(d_mqpar.values(), index=d_mqpar.keys()).convert_dtypes()\n", - "df_mqpar" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The number of threads used might differ" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_mqpar['numThreads'].value_counts()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The parameter files would need further parsing, which is skipped for now:\n", - " - `OrderedDict` would need to be flattend\n", - " - in the example below, it is not easy to see how entries should be easily combined\n", - " (list of `OrderedDict`s where only the `fastaFilePath` is different)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_mqpar.iloc[0].loc['fastaFiles']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "in order to see if there are different setting based on the string columns, drop duplicates\n", - "\n", - "- only one should remain" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_mqpar.select_dtypes('string').drop('numThreads', axis=1).drop_duplicates()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Peptides\n", - "\n", - "- peptides combined (combining different charged states): `peptides`\n", - "- single peptides (with differing charges): `evidence`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "pd.set_option('max_columns', 60)\n", - "\n", - "# mq_output = MaxQuantOutputDynamic(\n", - "# folder=folders[random.randint(0, len(paths_peptides.files)-1)])\n", - "mq_output.peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.evidence" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Create peptide intensity dumps for each MQ outputfolder\n", - "\n", - "- idea was: dump peptides found for each (unique) gene\n", - " - creates a `json` file for each gene with the gene contained\n", - "\n", - "- decision: discard\n", - " - rather dump peptide information per sample. Mapping of peptides to gene can be done\n", - " using the fasta file on the pytorch level." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# folders[:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Check if the output folder contains already parsed files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# import json\n", - "\n", - "# with open(src.config.FN_FASTA_DB) as f:\n", - "# data_fasta = json.load(f)\n", - "# print(f'Number of proteins in fasta file DB: {len(data_fasta)}')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# %%time\n", - "# FOLDER_PEP_PER_GENE = Path(FOLDER_PROCESSED) / 'agg_peptides_per_gene'\n", - "# FOLDER_PEP_PER_GENE.mkdir(parents=True, exist_ok=True)\n", - "# set_previously_loaded = {folder.name for folder in FOLDER_PEP_PER_GENE.iterdir()}\n", - "\n", - "# FORCE = True\n", - "\n", - "# for folder in folders:\n", - "# if folder.name in set_previously_loaded and not FORCE and (folder / '0_completness_all_genes.json').exists():\n", - "# pass\n", - "# else:\n", - "# logger.info(f'\\n\\nProcess: {folder.name}')\n", - "# mq_output = MaxQuantOutputDynamic(folder)\n", - "# peptide_extractor = ExtractFromPeptidesTxt(\n", - "# out_folder=FOLDER_PEP_PER_GENE, mq_output_object=mq_output, fasta_db=data_fasta)\n", - "# completeness_per_gene = peptide_extractor()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Theoretial Peptides from used fasta-file\n", - "\n", - "> `01_explore_FASTA.ipynb` (formely `misc_FASTA_tryptic_digest.ipynb`)\n", - "\n", - "- check if peptides are part of theoretical peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "file_extension": ".py", - "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.8.15" - }, - "mimetype": "text/x-python", - "name": "python", - "npconvert_exporter": "python", - "pygments_lexer": "ipython3", - "toc-autonumbering": true, - "version": 3, - "vscode": { - "interpreter": { - "hash": "79d0f0394ff693752da6f78eb84feea9ce495e5d1d56e189f7fad91f86783599" - } - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/erda_00_maxquant_file_reader.py b/project/erda_00_maxquant_file_reader.py deleted file mode 100644 index 74e572164..000000000 --- a/project/erda_00_maxquant_file_reader.py +++ /dev/null @@ -1,266 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# %% [markdown] Collapsed="false" -# # MaxQuant (MQ) Output-Files -# -# Compare a single experiment -# -# Files compared: -# 1. `Summary.txt` -# 2. `mqpar.xml` -# 3. `peptides.txt` -# 4. `proteins.txt` -# -# There is are many files more, where several files seem to be available in several times in different formats. - -# %% -import os -import sys -import logging -from pathlib import Path -import random -from tqdm.notebook import tqdm - -import pandas as pd -import ipywidgets as widgets - -from vaep.io import PathsList -from vaep.io.mq import MaxQuantOutputDynamic -from vaep.io.mq import ExtractFromPeptidesTxt -import vaep.io.mq as mq - - -from src.file_utils import load_summary, load_mqpar_xml -from vaep.logging import setup_logger_w_file - -################## -##### CONFIG ##### -################## -from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED -from config import FOLDER_KEY # defines how filenames are parsed for use as indices - -from config import FOLDER_DATA # project folder for storing the data -print(f"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}") - -################## -### Logging ###### -################## - -# Delete Jupyter notebook root logger handler -root_logger = logging.getLogger() -root_logger.handlers = [] - -logger = logging.getLogger('vaep') -logger = setup_logger_w_file(logger, fname_base='log_00_maxquant_file_reader') - -logger.info('Start with handlers: \n' + "\n".join(f"- {repr(log_)}" for log_ in logger.handlers)) - -# %% -folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir()] - -# %% -folders_dict = {folder.name: folder for folder in sorted(folders)} -assert len(folders_dict) == len(folders), "Non unique file names" - -# %% Collapsed="false" -# w_file = widgets.Dropdown(options=[folder for folder in folders], description='View files') -w_file = widgets.Dropdown(options=folders_dict, description='View files') -w_file - -# %% -mq_output = MaxQuantOutputDynamic(w_file.value) -mq_output - -# %% [markdown] -# Results will be saved in a subfolder under `vaep/project/data` using the -# name of the specified input-folder per default. Change to your liking: - -# %% [markdown] -# > Go to the block you are interested in! - -# %% [markdown] Collapsed="false" -# ## MQ Summary files - -# %% -mq_output.summary.iloc[0].to_dict() - -# %% [markdown] Collapsed="false" -# ### File Handler -# -# - dictionary of run name to run output folder -# - find class with expected output folders - -# %% Collapsed="false" -# # load_summary?? - -# %% [markdown] Collapsed="false" -# ### Summaries -# -# - aggregated in `vaep/project/erda_01_mq_aggregate_summaries.ipynb` -# - file selection based on summaries for further analysis thereafter - -# %% -# paths_summaries = [str(folder / 'summary.txt') for folder in folders_dict.values()] - -# %% Collapsed="false" -# # if paths_summaries.files: -# if folders_dict: -# # df, names, failed = process_files(handler_fct=load_summary, filepaths=paths_summaries.files, key=FOLDER_KEY, relative_to='paths_summaries.folder') -# df, names, failed = process_files(handler_fct=load_summary, filepaths=paths_summaries, key=FOLDER_KEY, relative_to=None) -# df.columns = names -# print(f"Number of failed reads: {len(failed)}") -# display(df) - -# %% -# # if paths_summaries.files: -# if paths_summaries: -# df.to_csv(os.path.join(FOLDER_PROCESSED, 'all_summary_txt.csv')) -# df.to_pickle(os.path.join(FOLDER_PROCESSED, 'all_summary_txt.pkl')) - -# %% [markdown] -# - SIL - MS2 based on precursor which was a set of peaks -# - PEAK - MS2 scan based on a single peak on precursor spectrum -# - ISO - isotopic pattern detection -# - -# %% -# # if paths_summaries.files: -# if paths_summaries: -# MS_spectra = df.loc[['MS', 'MS/MS Identified']].T.astype('int64') -# mask = MS_spectra['MS/MS Identified'] > 0 -# display(MS_spectra.loc[mask].describe()) -# MS_spectra.to_csv(os.path.join(FOLDER_PROCESSED, 'overview_stats.csv')) - -# %% [markdown] Collapsed="false" -# ## MaxQuant Parameter File -# -# - partly in a separate subfolder -# - mainly in run folders -# - rebase on folders_dictionary (check for `.xml` files in all folders) - -# %% -mqpar_files = (Path(FOLDER_DATA) / 'mqpar_files') - -mqpar_files = [file for file in mqpar_files.iterdir() if file.suffix == '.xml'] -len(mqpar_files) # nested search needed - -# %% Collapsed="false" -w_file = widgets.Dropdown(options=mqpar_files, description='Select a file') -w_file - -# %% [markdown] Collapsed="false" -# ### Parameter Files - -# %% Collapsed="false" -fname_mqpar_xml = os.path.join(FOLDER_PROCESSED, 'peptide_intensities.{}') - -d_mqpar = dict() -for file in tqdm(mqpar_files): - d_mqpar[file.stem] = load_mqpar_xml(file)['MaxQuantParams'] - -df_mqpar = pd.DataFrame(d_mqpar.values(), index=d_mqpar.keys()).convert_dtypes() -df_mqpar - -# %% [markdown] -# The number of threads used might differ - -# %% -df_mqpar['numThreads'].value_counts() - -# %% [markdown] -# The parameter files would need further parsing, which is skipped for now: -# - `OrderedDict` would need to be flattend -# - in the example below, it is not easy to see how entries should be easily combined -# (list of `OrderedDict`s where only the `fastaFilePath` is different) - -# %% -df_mqpar.iloc[0].loc['fastaFiles'] - -# %% [markdown] -# in order to see if there are different setting based on the string columns, drop duplicates -# -# - only one should remain - -# %% -df_mqpar.select_dtypes('string').drop('numThreads', axis=1).drop_duplicates() - -# %% [markdown] Collapsed="false" -# ## Peptides -# -# - peptides combined (combining different charged states): `peptides` -# - single peptides (with differing charges): `evidence` - -# %% Collapsed="false" -pd.set_option('max_columns', 60) - -# mq_output = MaxQuantOutputDynamic( -# folder=folders[random.randint(0, len(paths_peptides.files)-1)]) -mq_output.peptides - -# %% -mq_output.evidence - -# %% -mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands - -# %% [markdown] Collapsed="false" -# ### Create peptide intensity dumps for each MQ outputfolder -# -# - idea was: dump peptides found for each (unique) gene -# - creates a `json` file for each gene with the gene contained -# -# - decision: discard -# - rather dump peptide information per sample. Mapping of peptides to gene can be done -# using the fasta file on the pytorch level. - -# %% -# folders[:10] - -# %% [markdown] -# Check if the output folder contains already parsed files - -# %% -# import json - -# with open(src.config.FN_FASTA_DB) as f: -# data_fasta = json.load(f) -# print(f'Number of proteins in fasta file DB: {len(data_fasta)}') - -# %% -# # %%time -# FOLDER_PEP_PER_GENE = Path(FOLDER_PROCESSED) / 'agg_peptides_per_gene' -# FOLDER_PEP_PER_GENE.mkdir(parents=True, exist_ok=True) -# set_previously_loaded = {folder.name for folder in FOLDER_PEP_PER_GENE.iterdir()} - -# FORCE = True - -# for folder in folders: -# if folder.name in set_previously_loaded and not FORCE and (folder / '0_completness_all_genes.json').exists(): -# pass -# else: -# logger.info(f'\n\nProcess: {folder.name}') -# mq_output = MaxQuantOutputDynamic(folder) -# peptide_extractor = ExtractFromPeptidesTxt( -# out_folder=FOLDER_PEP_PER_GENE, mq_output_object=mq_output, fasta_db=data_fasta) -# completeness_per_gene = peptide_extractor() - -# %% [markdown] Collapsed="false" -# ## Theoretial Peptides from used fasta-file -# -# > `01_explore_FASTA.ipynb` (formely `misc_FASTA_tryptic_digest.ipynb`) -# -# - check if peptides are part of theoretical peptides - -# %% Collapsed="false" diff --git a/project/erda_01_mq_select_runs.ipynb b/project/erda_01_mq_select_runs.ipynb deleted file mode 100644 index 875fcb525..000000000 --- a/project/erda_01_mq_select_runs.ipynb +++ /dev/null @@ -1,423 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "# MaxQuant (MQ) Output-Files\n", - "\n", - "Files compared:\n", - "1. `Summary.txt`\n", - "2. `mqpar.xml`\n", - "3. `peptides.txt`\n", - "4. `proteins.txt`\n", - "\n", - "There is are many files more, where several files seem to be available in several times in different formats." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import logging\n", - "from pathlib import Path, PurePosixPath\n", - "import yaml\n", - "\n", - "import ipywidgets as widgets\n", - "import pandas as pd\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from vaep.io.data_objects import MqAllSummaries\n", - "from vaep import plotting\n", - "from vaep.io.mq import MaxQuantOutputDynamic\n", - "\n", - "import config\n", - "from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED\n", - "\n", - "\n", - "##################\n", - "### Logging ######\n", - "##################\n", - "\n", - "# Setup logging in notebooks\n", - "from vaep.logging import setup_nb_logger\n", - "setup_nb_logger()\n", - "logger = logging.getLogger()\n", - "\n", - "logging.info('Start with handlers: \\n' + \"\\n\".join(f\"- {repr(log_)}\" for log_ in logger.handlers))\n", - "\n", - "# Other imports\n", - "\n", - "\n", - "##################\n", - "##### CONFIG #####\n", - "##################\n", - "\n", - "ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml')\n", - "MAP_FOLDER_PATH = Path('config/file_paths')\n", - "FPATH_ALL_SUMMARIES = FOLDER_PROCESSED / 'all_summaries.json'\n", - "FN_RAWFILE_METADATA = 'data/rawfile_metadata.csv'\n", - "\n", - "logger.info(f\"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir()\n", - " and not folder.name.startswith('.')]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "folders_dict = {folder.name: folder for folder in sorted(folders)}\n", - "assert len(folders_dict) == len(folders), \"Non unique file names\"\n", - "\n", - "with open(MAP_FOLDER_PATH, 'w') as f:\n", - " yaml.dump({k: str(PurePosixPath(v)) for k, v in folders_dict.items()}, f)\n", - "logger.info(f\"Save map of file names to file paths to: {str(MAP_FOLDER_PATH)}\")\n", - "\n", - "# w_file = widgets.Dropdown(options=[folder for folder in folders], description='View files')\n", - "w_file = widgets.Dropdown(options=folders_dict, description='View files')\n", - "w_file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output = MaxQuantOutputDynamic(w_file.value)\n", - "mq_output" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(f\"Results will be saved in subfolders in\\n\\t{str(FOLDER_PROCESSED.absolute())}\"\n", - " \"\\nusing the name of the specified input-folder per default. Change to your liking.\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "> Go to the block you are interested in!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Summaries Data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "pd.options.display.max_columns = 49\n", - "mq_all_summaries = MqAllSummaries(FPATH_ALL_SUMMARIES)\n", - "mq_all_summaries.load_new_samples(folders=folders)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "if mq_all_summaries.empty_folders:\n", - " print(mq_all_summaries.empty_folders)\n", - " with open('log_empty_folder.txt', 'a') as f:\n", - " f.writelines(mq_all_summaries.empty_folders)\n", - "print(f\"In total processed: {len(mq_all_summaries):5}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "pd.options.display.max_columns = len(mq_all_summaries.df.columns)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_all_summaries.df.info()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- SIL - MS2 based on precursor which was a set of peaks\n", - "- PEAK - MS2 scan based on a single peak on precursor spectrum\n", - "- ISO - isotopic pattern detection\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class col_summary:\n", - " MS1 = 'MS'\n", - " MS2 = 'MS/MS'\n", - " MS2_identified = 'MS/MS Identified'\n", - " peptides_identified = 'Peptide Sequences Identified' # 'peptides.txt' should have this number of peptides\n", - "\n", - "\n", - "df = mq_all_summaries.df\n", - "if df is not None:\n", - " MS_spectra = df[[col_summary.MS1, col_summary.MS2, col_summary.MS2_identified, col_summary.peptides_identified]]\n", - "\n", - " def compute_summary(threshold_identified):\n", - " mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified\n", - " display(MS_spectra.loc[mask].describe(np.linspace(0.05, 0.95, 10)))\n", - "\n", - " w_ions_range = widgets.IntSlider(value=15_000, min=.0, max=MS_spectra[col_summary.peptides_identified].max())\n", - " display(widgets.interactive(compute_summary, threshold_identified=w_ions_range))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = MS_spectra[col_summary.peptides_identified] >= w_ions_range.value\n", - "logger.warning(f\"Save {mask.sum()} file names to configuration file of selected samples: \"\n", - " f\"{ELIGABLE_FILES_YAML} \"\n", - " f\"based on a minimum of {w_ions_range.value} peptides.\")\n", - "idx_selected = MS_spectra.loc[mask].index\n", - "MS_spectra.loc[idx_selected]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Select Date Range\n", - "\n", - "- based on metadata" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_meta_rawfiles = pd.read_csv(FN_RAWFILE_METADATA, header=[0, 1], index_col=0)\n", - "date_col = ('FileProperties', 'Content Creation Date')\n", - "df_meta_rawfiles[date_col] = pd.to_datetime(\n", - " df_meta_rawfiles[date_col])\n", - "df_meta_rawfiles = df_meta_rawfiles.loc[idx_selected]\n", - "df_meta_rawfiles.sort_values(date_col, inplace=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "w_date_range = widgets.SelectionRangeSlider(options=df_meta_rawfiles[date_col], value=[\n", - " min(df_meta_rawfiles[date_col]), max(df_meta_rawfiles[date_col])])\n", - "\n", - "\n", - "def show(range):\n", - " mask = df_meta_rawfiles[date_col].between(*range)\n", - " df_view = MS_spectra.loc[idx_selected].loc[mask]\n", - " display(df_view)\n", - "\n", - "\n", - "int_date_range = widgets.interactive(show, range=w_date_range)\n", - "display(int_date_range)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = df_meta_rawfiles[date_col].between(*w_date_range.value)\n", - "idx_selected = mask.loc[mask].index\n", - "idx_selected" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Write out selected, eligable files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "with open(ELIGABLE_FILES_YAML, 'w') as f:\n", - " yaml.dump(data={'files': idx_selected.to_list()}, stream=f)\n", - "logger.info(f\"Dumped yaml file with eligable files under key 'files' to {str(ELIGABLE_FILES_YAML)}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Plot number of samples\n", - "\n", - "- binned by 10k steps" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_max = MS_spectra[col_summary.peptides_identified].max() + 10_001\n", - "fig, ax = plt.subplots(figsize=(10, 10))\n", - "_ = MS_spectra[col_summary.peptides_identified].hist(\n", - " bins=range(0, _max, 10_000),\n", - " legend=True,\n", - " ax=ax)\n", - "fig.suptitle('Number of samples, binned in 10K steps.')\n", - "fig.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# including folders with 0 identified peptides\n", - "MS_spectra[col_summary.peptides_identified].mean(), MS_spectra[col_summary.peptides_identified].std()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def calc_cutoff(threshold=1):\n", - " s = MS_spectra[col_summary.peptides_identified]\n", - " mask = s >= threshold\n", - " s = s.loc[mask]\n", - " display(f\"Threshold selected (inclusive): {threshold} \")\n", - " display(f\"mean: {s.mean():.2f}, std-dev: {s.std():.2f}\")\n", - "\n", - "\n", - "# calc_cutoff()\n", - "display(widgets.interactive(calc_cutoff, threshold=widgets.IntSlider(\n", - " value=10000.0, min=.0, max=MS_spectra[col_summary.peptides_identified].max())))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fig, axes = plt.subplots(2, 2, figsize=(20, 20), sharex=True)\n", - "\n", - "ylim_hist = (0, 600)\n", - "xlim_dens = (0, 70_000)\n", - "\n", - "ax = axes[0, 0]\n", - "ax = mq_all_summaries.df[col_summary.peptides_identified].plot(\n", - " kind='hist', bins=50, title=\"Histogram including samples with zero identified peptides\", grid=True, ax=ax, ylim=ylim_hist)\n", - "ax = axes[1, 0]\n", - "_ = mq_all_summaries.df[col_summary.peptides_identified].astype(float).plot.kde(\n", - " ax=ax, title=\"Density plot including samples with zero identified peptides.\", xlim=xlim_dens)\n", - "\n", - "threshold_m2_identified = 15_000\n", - "mask = mq_all_summaries.df[col_summary.peptides_identified] >= threshold_m2_identified\n", - "\n", - "ax = axes[0, 1]\n", - "ax = mq_all_summaries.df.loc[mask,\n", - " col_summary.peptides_identified].plot(kind='hist',\n", - " bins=40,\n", - " title=f\"Histogram including samples with {threshold_m2_identified:,d} and more identified peptides\",\n", - " grid=True,\n", - " ax=ax,\n", - " ylim=ylim_hist)\n", - "ax = axes[1, 1]\n", - "_ = mq_all_summaries.df.loc[mask, col_summary.peptides_identified].astype(float).plot.kde(\n", - " ax=ax, title=f\"Density plot including samples with {threshold_m2_identified:,d} and more identified peptides.\", xlim=xlim_dens)\n", - "\n", - "plotting._savefig(fig, name='distribution_peptides_in_samples', folder=config.FIGUREFOLDER)" - ] - } - ], - "metadata": { - "file_extension": ".py", - "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.8.15" - }, - "mimetype": "text/x-python", - "name": "python", - "npconvert_exporter": "python", - "pygments_lexer": "ipython3", - "toc-autonumbering": true, - "version": 3 - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/erda_01_mq_select_runs.py b/project/erda_01_mq_select_runs.py deleted file mode 100644 index 6ae571352..000000000 --- a/project/erda_01_mq_select_runs.py +++ /dev/null @@ -1,253 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# %% [markdown] Collapsed="false" -# # MaxQuant (MQ) Output-Files -# -# Files compared: -# 1. `Summary.txt` -# 2. `mqpar.xml` -# 3. `peptides.txt` -# 4. `proteins.txt` -# -# There is are many files more, where several files seem to be available in several times in different formats. - -# %% -import logging -from pathlib import Path, PurePosixPath -import yaml - -import ipywidgets as widgets -import pandas as pd -import numpy as np -import matplotlib.pyplot as plt - -from vaep.io.data_objects import MqAllSummaries -from vaep import plotting -from vaep.io.mq import MaxQuantOutputDynamic - -import config -from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED - - -################## -### Logging ###### -################## - -# Setup logging in notebooks -from vaep.logging import setup_nb_logger -setup_nb_logger() -logger = logging.getLogger() - -logging.info('Start with handlers: \n' + "\n".join(f"- {repr(log_)}" for log_ in logger.handlers)) - -# Other imports - - -################## -##### CONFIG ##### -################## - -ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml') -MAP_FOLDER_PATH = Path('config/file_paths') -FPATH_ALL_SUMMARIES = FOLDER_PROCESSED / 'all_summaries.json' -FN_RAWFILE_METADATA = 'data/rawfile_metadata.csv' - -logger.info(f"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}") - -# %% Collapsed="false" -folders = [folder for folder in Path(FOLDER_MQ_TXT_DATA).iterdir() if folder.is_dir() - and not folder.name.startswith('.')] - -# %% Collapsed="false" -folders_dict = {folder.name: folder for folder in sorted(folders)} -assert len(folders_dict) == len(folders), "Non unique file names" - -with open(MAP_FOLDER_PATH, 'w') as f: - yaml.dump({k: str(PurePosixPath(v)) for k, v in folders_dict.items()}, f) -logger.info(f"Save map of file names to file paths to: {str(MAP_FOLDER_PATH)}") - -# w_file = widgets.Dropdown(options=[folder for folder in folders], description='View files') -w_file = widgets.Dropdown(options=folders_dict, description='View files') -w_file - -# %% -mq_output = MaxQuantOutputDynamic(w_file.value) -mq_output - -# %% -print(f"Results will be saved in subfolders in\n\t{str(FOLDER_PROCESSED.absolute())}" - "\nusing the name of the specified input-folder per default. Change to your liking.") - -# %% [markdown] -# > Go to the block you are interested in! - -# %% [markdown] Collapsed="false" -# ### Summaries Data - -# %% -# %%time -pd.options.display.max_columns = 49 -mq_all_summaries = MqAllSummaries(FPATH_ALL_SUMMARIES) -mq_all_summaries.load_new_samples(folders=folders) - -# %% Collapsed="false" -if mq_all_summaries.empty_folders: - print(mq_all_summaries.empty_folders) - with open('log_empty_folder.txt', 'a') as f: - f.writelines(mq_all_summaries.empty_folders) -print(f"In total processed: {len(mq_all_summaries):5}") - -# %% Collapsed="false" -pd.options.display.max_columns = len(mq_all_summaries.df.columns) - -# %% -mq_all_summaries.df.info() - - -# %% [markdown] -# - SIL - MS2 based on precursor which was a set of peaks -# - PEAK - MS2 scan based on a single peak on precursor spectrum -# - ISO - isotopic pattern detection -# - -# %% -class col_summary: - MS1 = 'MS' - MS2 = 'MS/MS' - MS2_identified = 'MS/MS Identified' - peptides_identified = 'Peptide Sequences Identified' # 'peptides.txt' should have this number of peptides - - -df = mq_all_summaries.df -if df is not None: - MS_spectra = df[[col_summary.MS1, col_summary.MS2, col_summary.MS2_identified, col_summary.peptides_identified]] - - def compute_summary(threshold_identified): - mask = MS_spectra[col_summary.peptides_identified] >= threshold_identified - display(MS_spectra.loc[mask].describe(np.linspace(0.05, 0.95, 10))) - - w_ions_range = widgets.IntSlider(value=15_000, min=.0, max=MS_spectra[col_summary.peptides_identified].max()) - display(widgets.interactive(compute_summary, threshold_identified=w_ions_range)) - -# %% -mask = MS_spectra[col_summary.peptides_identified] >= w_ions_range.value -logger.warning(f"Save {mask.sum()} file names to configuration file of selected samples: " - f"{ELIGABLE_FILES_YAML} " - f"based on a minimum of {w_ions_range.value} peptides.") -idx_selected = MS_spectra.loc[mask].index -MS_spectra.loc[idx_selected] - -# %% [markdown] -# ### Select Date Range -# -# - based on metadata - -# %% -df_meta_rawfiles = pd.read_csv(FN_RAWFILE_METADATA, header=[0, 1], index_col=0) -date_col = ('FileProperties', 'Content Creation Date') -df_meta_rawfiles[date_col] = pd.to_datetime( - df_meta_rawfiles[date_col]) -df_meta_rawfiles = df_meta_rawfiles.loc[idx_selected] -df_meta_rawfiles.sort_values(date_col, inplace=True) - -# %% -w_date_range = widgets.SelectionRangeSlider(options=df_meta_rawfiles[date_col], value=[ - min(df_meta_rawfiles[date_col]), max(df_meta_rawfiles[date_col])]) - - -def show(range): - mask = df_meta_rawfiles[date_col].between(*range) - df_view = MS_spectra.loc[idx_selected].loc[mask] - display(df_view) - - -int_date_range = widgets.interactive(show, range=w_date_range) -display(int_date_range) - -# %% -mask = df_meta_rawfiles[date_col].between(*w_date_range.value) -idx_selected = mask.loc[mask].index -idx_selected - -# %% [markdown] -# ### Write out selected, eligable files - -# %% -with open(ELIGABLE_FILES_YAML, 'w') as f: - yaml.dump(data={'files': idx_selected.to_list()}, stream=f) -logger.info(f"Dumped yaml file with eligable files under key 'files' to {str(ELIGABLE_FILES_YAML)}") - -# %% [markdown] -# ## Plot number of samples -# -# - binned by 10k steps - -# %% -_max = MS_spectra[col_summary.peptides_identified].max() + 10_001 -fig, ax = plt.subplots(figsize=(10, 10)) -_ = MS_spectra[col_summary.peptides_identified].hist( - bins=range(0, _max, 10_000), - legend=True, - ax=ax) -fig.suptitle('Number of samples, binned in 10K steps.') -fig.tight_layout() - -# %% -# including folders with 0 identified peptides -MS_spectra[col_summary.peptides_identified].mean(), MS_spectra[col_summary.peptides_identified].std() - - -# %% -def calc_cutoff(threshold=1): - s = MS_spectra[col_summary.peptides_identified] - mask = s >= threshold - s = s.loc[mask] - display(f"Threshold selected (inclusive): {threshold} ") - display(f"mean: {s.mean():.2f}, std-dev: {s.std():.2f}") - - -# calc_cutoff() -display(widgets.interactive(calc_cutoff, threshold=widgets.IntSlider( - value=10000.0, min=.0, max=MS_spectra[col_summary.peptides_identified].max()))) - -# %% -fig, axes = plt.subplots(2, 2, figsize=(20, 20), sharex=True) - -ylim_hist = (0, 600) -xlim_dens = (0, 70_000) - -ax = axes[0, 0] -ax = mq_all_summaries.df[col_summary.peptides_identified].plot( - kind='hist', bins=50, title="Histogram including samples with zero identified peptides", grid=True, ax=ax, ylim=ylim_hist) -ax = axes[1, 0] -_ = mq_all_summaries.df[col_summary.peptides_identified].astype(float).plot.kde( - ax=ax, title="Density plot including samples with zero identified peptides.", xlim=xlim_dens) - -threshold_m2_identified = 15_000 -mask = mq_all_summaries.df[col_summary.peptides_identified] >= threshold_m2_identified - -ax = axes[0, 1] -ax = mq_all_summaries.df.loc[mask, - col_summary.peptides_identified].plot(kind='hist', - bins=40, - title=f"Histogram including samples with {threshold_m2_identified:,d} and more identified peptides", - grid=True, - ax=ax, - ylim=ylim_hist) -ax = axes[1, 1] -_ = mq_all_summaries.df.loc[mask, col_summary.peptides_identified].astype(float).plot.kde( - ax=ax, title=f"Density plot including samples with {threshold_m2_identified:,d} and more identified peptides.", xlim=xlim_dens) - -plotting._savefig(fig, name='distribution_peptides_in_samples', folder=config.FIGUREFOLDER) diff --git a/project/erda_02_mq_count_features.ipynb b/project/erda_02_mq_count_features.ipynb deleted file mode 100644 index cb7585347..000000000 --- a/project/erda_02_mq_count_features.ipynb +++ /dev/null @@ -1,988 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Count and select features of all samples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "from collections import Counter\n", - "import os\n", - "import logging\n", - "from pathlib import Path\n", - "import random\n", - "import yaml\n", - "\n", - "import pandas as pd\n", - "from tqdm.notebook import tqdm\n", - "\n", - "import vaep.pandas\n", - "from vaep.io.data_objects import PeptideCounter\n", - "from vaep.io import mq\n", - "from vaep.io.mq import MaxQuantOutputDynamic\n", - "\n", - "##### CONFIG #####\n", - "from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED\n", - "from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES\n", - "\n", - "### Logging setup ######\n", - "from vaep.logging import setup_nb_logger\n", - "setup_nb_logger()\n", - "\n", - "logging.info(f\"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Use samples previously loaded. Specified MQ output folders are in `eligable_files.yaml`\n", - "\n", - "```yaml\n", - "# example of eligable_files.yaml\n", - "files:\n", - " - example_folder\n", - "```\n", - "\n", - "and the name to folder path are in `file_paths.yaml`\n", - "\n", - "```yaml\n", - "# example of file_paths.yaml\n", - "example_folder: path/to/example_folder\n", - "```\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml') # acutally MQ txt folders, not files...\n", - "MAP_FOLDER_PATH = Path('config/file_paths.yaml')\n", - "\n", - "with open(ELIGABLE_FILES_YAML) as f:\n", - " files = set(yaml.safe_load(f)['files'])\n", - " logging.info(f\"Found a total of {len(files):,d} eligable files.\")\n", - "with open(MAP_FOLDER_PATH) as f:\n", - " folders_dict = yaml.safe_load(f)\n", - " folders_dict = {folder: folders_dict[folder] for folder in files} # only select folders selected\n", - "\n", - "folders = [Path(folders_dict[folder]) for folder in files]\n", - "assert len(files) == len(folders_dict) == len(folders)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id\n", - "df_ids = pd.read_csv(fn_id_old_new, index_col=0)\n", - "df_ids" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Select files and create list of folders" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "lines_to_next_cell": 2, - "tags": [] - }, - "outputs": [], - "source": [ - "files = [file for file in files if file in df_ids.index]\n", - "folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in files}\n", - "# folders_dict = {p.stem : p.parent / p.stem for p in folders_dict}\n", - "# folders_dict\n", - "folders = [Path(folder_path) for folder_path in folders_dict.values()]\n", - "len(folders)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "OVERWRITE = False\n", - "OVERWRITE = True\n", - "\n", - "\n", - "FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Random example - peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "pd.set_option('display.max_columns', 60)\n", - "random_folder, random_path = random.sample(folders_dict.items(), 1)[0]\n", - "mq_output = MaxQuantOutputDynamic(random_path)\n", - "print(f\"peptides.txt from {random_folder!s}\")\n", - "mq_output.peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "use_columns = mq_output.peptides.columns[33:45]\n", - "df = mq_output.peptides[use_columns].convert_dtypes() # .to_json('test.json')\n", - "df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The above is done in the function for loading and processing peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# internals: processing file (includes filtering)\n", - "peptides = vaep.io.data_objects.load_process_peptides(random_path,\n", - " use_cols=mq.COLS_ + ['Potential contaminant',\n", - " 'Reverse',\n", - " mq.mq_col.SEQUENCE,\n", - " 'PEP',\n", - " 'id',\n", - " 'Protein group IDs',\n", - " 'Evidence IDs',\n", - " ])\n", - "peptides" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Count aggregated peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "peptide_counter = PeptideCounter(FNAME_C_PEPTIDES, overwrite=OVERWRITE)\n", - "peptide_counter" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "if peptide_counter.loaded:\n", - " print(peptide_counter.counter.most_common(10),\n", - " len(peptide_counter.loaded),\n", - " sep='\\n')\n", - "else:\n", - " print('New file created.')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- creates peptide intensity dumps for each MQ outputfolder per default `count_peptides` function (default processing function for `PeptideCounter`)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "%%time\n", - "c = peptide_counter.sum_over_files(folders=folders)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "for k, v in tqdm(peptide_counter.dumps.items()):\n", - " old_name = v\n", - " new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv')\n", - " try:\n", - " os.rename(old_name, new_name)\n", - " except FileNotFoundError:\n", - " logging.warning(f\"File not found: {old_name}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "c.most_common(10) # peptide_counter.counter.most_common(10)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# To share as python file\n", - "N = 1000\n", - "with open(FOLDER_PROCESSED / f'most_common_{10}_peptides.py', 'w') as f:\n", - " f.write('import pandas as pd\\n\\n')\n", - "\n", - " # pprint.pformat list -> do this using standardlibrary\n", - " # https://docs.python.org/3/library/pprint.html\n", - " f.write(f\"most_common = [\\n \")\n", - " f.write(',\\n '.join(f\"{str(t)}\" for t in c.most_common(N)))\n", - " f.write(\"\\n]\\n\\n\")\n", - "\n", - " # peptide_counter.loaded()\n", - "\n", - " f.write(\"pd.DataFrame.from_records(most_common, index='Sequence', columns=['Sequence', 'counts'])\\n\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Random example - precursors\n", - "\n", - "- count peptides by charge state (which are aggregated in `peptides.txt`)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "evidence_cols = vaep.pandas.get_columns_accessor(mq_output.evidence.reset_index())\n", - "evidence_cols # vaep.mq get this list" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "evidence = mq_output.evidence.set_index(evidence_cols.Charge, append=True)\n", - "evidence" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Modifikationen könnten noch zum index hinzugefügt werden" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "evidence.Modifications.value_counts()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "vaep.pandas.prop_unique_index(evidence)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Using the protein AA sequence and it's charge as identifiers, does not yield a unique index.\n", - "\n", - "First potential contaminants and peptides with zero intensity (or missing intensity) can be removed from the table.\n", - "\n", - "These are apparently peptides identified by an MS2 spectrum but which could not be quantified by a MS1 scans" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "mask = evidence[evidence_cols.Intensity].isna()\n", - "evidence.loc[mask, evidence_cols.Type].value_counts()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "evidence_cols = vaep.io.data_objects.evidence_cols\n", - "use_cols = [\n", - " evidence_cols.mz,\n", - " evidence_cols.Protein_group_IDs,\n", - " evidence_cols.Intensity,\n", - " evidence_cols.Score,\n", - " evidence_cols.Reverse,\n", - " evidence_cols.Potential_contaminant]\n", - "\n", - "evidence_selected = vaep.io.data_objects.select_evidence(evidence[use_cols])\n", - "evidence_selected" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "evidence_selected = evidence_selected.sort_values(by=['Sequence', 'Charge', 'Score'], ascending=False)\n", - "evidence_selected" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "evidence_selected = vaep.pandas.select_max_by(\n", - " evidence_selected.reset_index(), [\n", - " evidence_cols.Sequence, evidence_cols.Charge], evidence_cols.Score)\n", - "evidence_selected" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "c = Counter()\n", - "c.update(evidence.index)\n", - "c.most_common(10)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "example = evidence.loc[c.most_common(10)[0][0]]\n", - "\n", - "vaep.pandas.show_columns_with_variation(example)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- `Type`: only `MULTI-MSMS` and `MULIT-SECPEP` are quantified (does this mean a matching MS1 spectrum?)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "evidence[evidence_cols.Type].value_counts()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Some peptides can be assigned to different protein group IDs (razor peptides)\n", - " - option: discared non-unique peptides (and Protein group IDs can be already a combination of several isotopes)\n", - " - option: select on `Score` or `Intensity` (is there a relationship?)\n", - " - option: select based on `Number of isotopic peaks`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "evidence[evidence_cols.Protein_group_IDs].value_counts()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The above is done in the function for loading and processing precursors" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# internals: processing file (includes filtering)\n", - "evidence = vaep.io.data_objects.load_process_evidence(random_path,\n", - " use_cols=[\n", - " mq.mq_evidence_cols.mz,\n", - " mq.mq_evidence_cols.id,\n", - " mq.mq_evidence_cols.Peptide_ID,\n", - " mq.mq_evidence_cols.Protein_group_IDs,\n", - " mq.mq_evidence_cols.Intensity,\n", - " mq.mq_evidence_cols.Score,\n", - " mq.mq_evidence_cols.Potential_contaminant,\n", - " mq.mq_evidence_cols.Reverse],\n", - " select_by='Score')\n", - "evidence" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Count precursors based on evidence files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "evidence_counter = vaep.io.data_objects.EvidenceCounter(FNAME_C_EVIDENCE, overwrite=OVERWRITE)\n", - "c = evidence_counter.sum_over_files(folders=folders)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "for k, v in tqdm(evidence_counter.dumps.items()):\n", - " old_name = v\n", - " new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv')\n", - " try:\n", - " os.rename(old_name, new_name)\n", - " except FileNotFoundError:\n", - " logging.warning(f\"File not found: {old_name}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Protein Groups\n", - "\n", - "- protein groups between files\n", - " - aggregate by GENE ?\n", - " -" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "mq_output.proteinGroups.describe(include='all')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "pg_cols = vaep.pandas.get_columns_accessor(mq_output.proteinGroups.reset_index())\n", - "pg_cols" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "use_cols = [\n", - " # pg_cols.Protein_IDs,\n", - " pg_cols.Majority_protein_IDs,\n", - " pg_cols.Gene_names,\n", - " pg_cols.Evidence_IDs,\n", - " pg_cols.Q_value,\n", - " pg_cols.Score,\n", - " pg_cols.Only_identified_by_site,\n", - " pg_cols.Reverse,\n", - " pg_cols.Potential_contaminant,\n", - " pg_cols.Intensity,\n", - "]\n", - "\n", - "pd.options.display.max_rows = 100\n", - "pd.options.display.min_rows = 40\n", - "mask = mq_output.proteinGroups[[pg_cols.Only_identified_by_site,\n", - " pg_cols.Reverse, pg_cols.Potential_contaminant]].notna().sum(axis=1) > 0\n", - "mq_output.proteinGroups.loc[mask, use_cols]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "msg = \"Omitting the data drops {0:.3f} % of the data.\"\n", - "print(msg.format(\n", - " mask.sum() / len(mask) * 100\n", - "))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "selection = mq_output.proteinGroups.loc[~mask, use_cols]\n", - "gene_counts = selection[pg_cols.Gene_names].value_counts() # Gene Names not unique\n", - "msg = 'proportion of entries with non-unique genes: {:.3f}'\n", - "print(msg.format(gene_counts.loc[gene_counts > 1].sum() / gene_counts.sum()))\n", - "gene_counts.head(20)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "mask = selection.Intensity > 0\n", - "msg = \"Proportion of non-zero Intensities: {:.3f} (zero_ count = {})\"\n", - "print(msg.format(mask.sum() / len(mask), (~mask).sum()))\n", - "selection.loc[~mask]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "selection = selection.loc[mask]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Some Proteins have no gene annotation\n", - " - P56181 -> mitochondrial\n", - "\n", - "In the online version of Uniprot these seems to be annotated (brief check).\n", - "So latest version probably has a gene annotation, so therefore these files are kept" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "gene_set = selection[pg_cols.Gene_names].str.split(';')\n", - "\n", - "col_loc_gene_names = selection.columns.get_loc(pg_cols.Gene_names)\n", - "_ = selection.insert(col_loc_gene_names + 1, 'Number of Genes', gene_set.apply(vaep.pandas.length))\n", - "\n", - "mask = gene_set.isna()\n", - "selection.loc[mask]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "cols = vaep.pandas.get_columns_accessor(selection)\n", - "gene_counts = vaep.pandas.counts_with_proportion(selection[cols.Number_of_Genes])\n", - "gene_counts" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Most `proteinGroups` have single genes assigned to them. If one only looks at gene sets,\n", - "one can increase uniquely identified `proteinGroups` further.\n", - "\n", - "> Can `geneGroups` (sets of `Gene Names`) be used instead of `proteinGroups`?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "gene_sets_counts = selection[cols.Gene_names].value_counts()\n", - "gene_sets_counts.value_counts()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Potential solutions:\n", - "- summarize intensity per gene. One of the isoforms seems to have the major proportion of intensity assigned.\n", - "- select maximum by score (higher scores seem to be related to higher intensity)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "non_unique_genes = gene_sets_counts.loc[gene_sets_counts > 1].index\n", - "\n", - "mask = selection[cols.Gene_names].isin(non_unique_genes)\n", - "selection.loc[mask].reset_index().set_index(cols.Gene_names).sort_index()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Protein Groups with Gene set with three and more genes:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "selection.loc[selection[cols.Number_of_Genes] > 2]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "logging.info(f\"Selection shape before dropping duplicates by gene: {selection.shape}\")\n", - "mask_no_gene = selection[pg_cols.Gene_names].isna()\n", - "selection_no_gene = selection.loc[mask_no_gene]\n", - "logging.info(f\"Entries without any gene annotation: {len(selection_no_gene)}\")\n", - "selection_no_gene" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "selection = vaep.pandas.select_max_by(df=selection.loc[~mask_no_gene].reset_index(), grouping_columns=[\n", - " pg_cols.Gene_names], selection_column=pg_cols.Score)\n", - "logging.info(f\"Selection shape after dropping duplicates by gene: {selection.shape}\")\n", - "selection = selection.set_index(pg_cols.Protein_IDs)\n", - "mask = selection[cols.Gene_names].isin(non_unique_genes)\n", - "selection.loc[mask]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "selection = pd.concat([selection, selection_no_gene])\n", - "selection" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The above is done in the function for loading and processing protein groups" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "vaep.io.data_objects.load_and_process_proteinGroups(random_path)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Count protein groups (genes) based on proteinGroups files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "protein_groups_counter = vaep.io.data_objects.ProteinGroupsCounter(FNAME_C_PG, overwrite=OVERWRITE)\n", - "c = protein_groups_counter.sum_over_files(folders=folders)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "for k, v in tqdm(protein_groups_counter.dumps.items()):\n", - " old_name = v\n", - " new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv')\n", - " try:\n", - " os.rename(old_name, new_name)\n", - " except FileNotFoundError:\n", - " logging.warning(f\"File not found: {old_name}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Over 400,000 protein groups were only identified once (as exactly this group)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "vaep.pandas.counts_with_proportion(pd.Series(c)) # Most proteinGroups are unique" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Count genes\n", - "Genes sets could be used to identify common features.\n", - "\n", - "> The assignment of isoforms to one proteinGroup or another might be volatile.\n", - "> A single (unique) peptide could lead to different assignments.\n", - "> Imputation on the evidence level could be a way to alleviate this problem\n", - "\n", - "- If genes set are not unique for a single run, one would have to decide which to take" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "gene_counter = vaep.io.data_objects.GeneCounter(FNAME_C_GENES, overwrite=OVERWRITE)\n", - "\n", - "if not gene_counter.dumps:\n", - " # empty dict, replace\n", - " gene_counter.dumps = dict(protein_groups_counter.dumps) # prot proteinGroups files to GeneCounter\n", - "pg_dumps = list(gene_counter.dumps.values())\n", - "\n", - "c_genes = gene_counter.sum_over_files(folders=pg_dumps)\n", - "\n", - "c_genes = pd.Series(c_genes)\n", - "vaep.pandas.counts_with_proportion(c_genes) # Most proteinGroups are unique" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Theoretial Peptides from used fasta-file\n", - "\n", - "> `01_explore_FASTA.ipynb` (formely `misc_FASTA_tryptic_digest.ipynb`)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - } - ], - "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.10.12" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/erda_02_mq_count_features.py b/project/erda_02_mq_count_features.py deleted file mode 100644 index ee0ebe189..000000000 --- a/project/erda_02_mq_count_features.py +++ /dev/null @@ -1,479 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.1 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# %% [markdown] -# # Count and select features of all samples - -# %% -from collections import Counter -import os -import logging -from pathlib import Path -import random -import yaml - -import pandas as pd -from tqdm.notebook import tqdm - -import vaep.pandas -from vaep.io.data_objects import PeptideCounter -from vaep.io import mq -from vaep.io.mq import MaxQuantOutputDynamic - -##### CONFIG ##### -from config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED -from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES - -### Logging setup ###### -from vaep.logging import setup_nb_logger -setup_nb_logger() - -logging.info(f"Search Raw-Files on path: {FOLDER_MQ_TXT_DATA}") - -# %% [markdown] -# Use samples previously loaded. Specified MQ output folders are in `eligable_files.yaml` -# -# ```yaml -# # example of eligable_files.yaml -# files: -# - example_folder -# ``` -# -# and the name to folder path are in `file_paths.yaml` -# -# ```yaml -# # example of file_paths.yaml -# example_folder: path/to/example_folder -# ``` -# -# - -# %% -ELIGABLE_FILES_YAML = Path('config/eligable_files.yaml') # acutally MQ txt folders, not files... -MAP_FOLDER_PATH = Path('config/file_paths.yaml') - -with open(ELIGABLE_FILES_YAML) as f: - files = set(yaml.safe_load(f)['files']) - logging.info(f"Found a total of {len(files):,d} eligable files.") -with open(MAP_FOLDER_PATH) as f: - folders_dict = yaml.safe_load(f) - folders_dict = {folder: folders_dict[folder] for folder in files} # only select folders selected - -folders = [Path(folders_dict[folder]) for folder in files] -assert len(files) == len(folders_dict) == len(folders) - -# %% -fn_id_old_new: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id -df_ids = pd.read_csv(fn_id_old_new, index_col=0) -df_ids - -# %% [markdown] -# Select files and create list of folders - -# %% -files = [file for file in files if file in df_ids.index] -folders_dict = {sample_id: FOLDER_MQ_TXT_DATA / sample_id for sample_id in files} -# folders_dict = {p.stem : p.parent / p.stem for p in folders_dict} -# folders_dict -folders = [Path(folder_path) for folder_path in folders_dict.values()] -len(folders) - - -# %% -OVERWRITE = False -OVERWRITE = True - - -FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES - -# %% [markdown] -# ## Random example - peptides - -# %% -pd.set_option('display.max_columns', 60) -random_folder, random_path = random.sample(folders_dict.items(), 1)[0] -mq_output = MaxQuantOutputDynamic(random_path) -print(f"peptides.txt from {random_folder!s}") -mq_output.peptides - -# %% -use_columns = mq_output.peptides.columns[33:45] -df = mq_output.peptides[use_columns].convert_dtypes() # .to_json('test.json') -df - -# %% -mq_output.peptides.Intensity # as is in peptides.txt, comma seperated thousands - -# %% [markdown] -# The above is done in the function for loading and processing peptides - -# %% -# internals: processing file (includes filtering) -peptides = vaep.io.data_objects.load_process_peptides(random_path, - use_cols=mq.COLS_ + ['Potential contaminant', - 'Reverse', - mq.mq_col.SEQUENCE, - 'PEP', - 'id', - 'Protein group IDs', - 'Evidence IDs', - ]) -peptides - -# %% [markdown] -# ## Count aggregated peptides - -# %% -peptide_counter = PeptideCounter(FNAME_C_PEPTIDES, overwrite=OVERWRITE) -peptide_counter - -# %% -if peptide_counter.loaded: - print(peptide_counter.counter.most_common(10), - len(peptide_counter.loaded), - sep='\n') -else: - print('New file created.') - -# %% [markdown] -# - creates peptide intensity dumps for each MQ outputfolder per default `count_peptides` function (default processing function for `PeptideCounter`) - -# %% -# %%time -c = peptide_counter.sum_over_files(folders=folders) - -# %% -for k, v in tqdm(peptide_counter.dumps.items()): - old_name = v - new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv') - try: - os.rename(old_name, new_name) - except FileNotFoundError: - logging.warning(f"File not found: {old_name}") - -# %% -c.most_common(10) # peptide_counter.counter.most_common(10) - -# %% -# To share as python file -N = 1000 -with open(FOLDER_PROCESSED / f'most_common_{10}_peptides.py', 'w') as f: - f.write('import pandas as pd\n\n') - - # pprint.pformat list -> do this using standardlibrary - # https://docs.python.org/3/library/pprint.html - f.write(f"most_common = [\n ") - f.write(',\n '.join(f"{str(t)}" for t in c.most_common(N))) - f.write("\n]\n\n") - - # peptide_counter.loaded() - - f.write("pd.DataFrame.from_records(most_common, index='Sequence', columns=['Sequence', 'counts'])\n") - -# %% [markdown] Collapsed="false" -# ## Random example - precursors -# -# - count peptides by charge state (which are aggregated in `peptides.txt`) - -# %% -evidence_cols = vaep.pandas.get_columns_accessor(mq_output.evidence.reset_index()) -evidence_cols # vaep.mq get this list - -# %% -evidence = mq_output.evidence.set_index(evidence_cols.Charge, append=True) -evidence - -# %% [markdown] -# Modifikationen könnten noch zum index hinzugefügt werden - -# %% -evidence.Modifications.value_counts() - -# %% -vaep.pandas.prop_unique_index(evidence) - -# %% [markdown] -# Using the protein AA sequence and it's charge as identifiers, does not yield a unique index. -# -# First potential contaminants and peptides with zero intensity (or missing intensity) can be removed from the table. -# -# These are apparently peptides identified by an MS2 spectrum but which could not be quantified by a MS1 scans - -# %% -mask = evidence[evidence_cols.Intensity].isna() -evidence.loc[mask, evidence_cols.Type].value_counts() - -# %% -evidence_cols = vaep.io.data_objects.evidence_cols -use_cols = [ - evidence_cols.mz, - evidence_cols.Protein_group_IDs, - evidence_cols.Intensity, - evidence_cols.Score, - evidence_cols.Reverse, - evidence_cols.Potential_contaminant] - -evidence_selected = vaep.io.data_objects.select_evidence(evidence[use_cols]) -evidence_selected - -# %% -evidence_selected = evidence_selected.sort_values(by=['Sequence', 'Charge', 'Score'], ascending=False) -evidence_selected - -# %% -evidence_selected = vaep.pandas.select_max_by( - evidence_selected.reset_index(), [ - evidence_cols.Sequence, evidence_cols.Charge], evidence_cols.Score) -evidence_selected - -# %% -c = Counter() -c.update(evidence.index) -c.most_common(10) - -# %% -example = evidence.loc[c.most_common(10)[0][0]] - -vaep.pandas.show_columns_with_variation(example) - -# %% [markdown] -# - `Type`: only `MULTI-MSMS` and `MULIT-SECPEP` are quantified (does this mean a matching MS1 spectrum?) - -# %% -evidence[evidence_cols.Type].value_counts() - -# %% [markdown] -# Some peptides can be assigned to different protein group IDs (razor peptides) -# - option: discared non-unique peptides (and Protein group IDs can be already a combination of several isotopes) -# - option: select on `Score` or `Intensity` (is there a relationship?) -# - option: select based on `Number of isotopic peaks` - -# %% -evidence[evidence_cols.Protein_group_IDs].value_counts() - -# %% [markdown] -# The above is done in the function for loading and processing precursors - -# %% -# internals: processing file (includes filtering) -evidence = vaep.io.data_objects.load_process_evidence(random_path, - use_cols=[ - mq.mq_evidence_cols.mz, - mq.mq_evidence_cols.id, - mq.mq_evidence_cols.Peptide_ID, - mq.mq_evidence_cols.Protein_group_IDs, - mq.mq_evidence_cols.Intensity, - mq.mq_evidence_cols.Score, - mq.mq_evidence_cols.Potential_contaminant, - mq.mq_evidence_cols.Reverse], - select_by='Score') -evidence - -# %% [markdown] -# ## Count precursors based on evidence files - -# %% -evidence_counter = vaep.io.data_objects.EvidenceCounter(FNAME_C_EVIDENCE, overwrite=OVERWRITE) -c = evidence_counter.sum_over_files(folders=folders) - -# %% -for k, v in tqdm(evidence_counter.dumps.items()): - old_name = v - new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv') - try: - os.rename(old_name, new_name) - except FileNotFoundError: - logging.warning(f"File not found: {old_name}") - -# %% [markdown] -# ## Protein Groups -# -# - protein groups between files -# - aggregate by GENE ? -# - - -# %% -mq_output.proteinGroups.describe(include='all') - -# %% -pg_cols = vaep.pandas.get_columns_accessor(mq_output.proteinGroups.reset_index()) -pg_cols - -# %% -use_cols = [ - # pg_cols.Protein_IDs, - pg_cols.Majority_protein_IDs, - pg_cols.Gene_names, - pg_cols.Evidence_IDs, - pg_cols.Q_value, - pg_cols.Score, - pg_cols.Only_identified_by_site, - pg_cols.Reverse, - pg_cols.Potential_contaminant, - pg_cols.Intensity, -] - -pd.options.display.max_rows = 100 -pd.options.display.min_rows = 40 -mask = mq_output.proteinGroups[[pg_cols.Only_identified_by_site, - pg_cols.Reverse, pg_cols.Potential_contaminant]].notna().sum(axis=1) > 0 -mq_output.proteinGroups.loc[mask, use_cols] - -# %% -msg = "Omitting the data drops {0:.3f} % of the data." -print(msg.format( - mask.sum() / len(mask) * 100 -)) - -# %% -selection = mq_output.proteinGroups.loc[~mask, use_cols] -gene_counts = selection[pg_cols.Gene_names].value_counts() # Gene Names not unique -msg = 'proportion of entries with non-unique genes: {:.3f}' -print(msg.format(gene_counts.loc[gene_counts > 1].sum() / gene_counts.sum())) -gene_counts.head(20) - -# %% -mask = selection.Intensity > 0 -msg = "Proportion of non-zero Intensities: {:.3f} (zero_ count = {})" -print(msg.format(mask.sum() / len(mask), (~mask).sum())) -selection.loc[~mask] - -# %% -selection = selection.loc[mask] - -# %% [markdown] -# Some Proteins have no gene annotation -# - P56181 -> mitochondrial -# -# In the online version of Uniprot these seems to be annotated (brief check). -# So latest version probably has a gene annotation, so therefore these files are kept - -# %% -gene_set = selection[pg_cols.Gene_names].str.split(';') - -col_loc_gene_names = selection.columns.get_loc(pg_cols.Gene_names) -_ = selection.insert(col_loc_gene_names + 1, 'Number of Genes', gene_set.apply(vaep.pandas.length)) - -mask = gene_set.isna() -selection.loc[mask] - -# %% -cols = vaep.pandas.get_columns_accessor(selection) -gene_counts = vaep.pandas.counts_with_proportion(selection[cols.Number_of_Genes]) -gene_counts - -# %% [markdown] -# Most `proteinGroups` have single genes assigned to them. If one only looks at gene sets, -# one can increase uniquely identified `proteinGroups` further. -# -# > Can `geneGroups` (sets of `Gene Names`) be used instead of `proteinGroups`? - -# %% -gene_sets_counts = selection[cols.Gene_names].value_counts() -gene_sets_counts.value_counts() - -# %% [markdown] -# Potential solutions: -# - summarize intensity per gene. One of the isoforms seems to have the major proportion of intensity assigned. -# - select maximum by score (higher scores seem to be related to higher intensity) - -# %% -non_unique_genes = gene_sets_counts.loc[gene_sets_counts > 1].index - -mask = selection[cols.Gene_names].isin(non_unique_genes) -selection.loc[mask].reset_index().set_index(cols.Gene_names).sort_index() - -# %% [markdown] -# Protein Groups with Gene set with three and more genes: - -# %% -selection.loc[selection[cols.Number_of_Genes] > 2] - -# %% -logging.info(f"Selection shape before dropping duplicates by gene: {selection.shape}") -mask_no_gene = selection[pg_cols.Gene_names].isna() -selection_no_gene = selection.loc[mask_no_gene] -logging.info(f"Entries without any gene annotation: {len(selection_no_gene)}") -selection_no_gene - -# %% -selection = vaep.pandas.select_max_by(df=selection.loc[~mask_no_gene].reset_index(), grouping_columns=[ - pg_cols.Gene_names], selection_column=pg_cols.Score) -logging.info(f"Selection shape after dropping duplicates by gene: {selection.shape}") -selection = selection.set_index(pg_cols.Protein_IDs) -mask = selection[cols.Gene_names].isin(non_unique_genes) -selection.loc[mask] - -# %% -selection = pd.concat([selection, selection_no_gene]) -selection - -# %% [markdown] -# The above is done in the function for loading and processing protein groups - -# %% -vaep.io.data_objects.load_and_process_proteinGroups(random_path) - -# %% [markdown] -# ## Count protein groups (genes) based on proteinGroups files - -# %% -protein_groups_counter = vaep.io.data_objects.ProteinGroupsCounter(FNAME_C_PG, overwrite=OVERWRITE) -c = protein_groups_counter.sum_over_files(folders=folders) - -# %% -for k, v in tqdm(protein_groups_counter.dumps.items()): - old_name = v - new_name = v.parent / (df_ids.loc[k, 'new_sample_id'] + '.csv') - try: - os.rename(old_name, new_name) - except FileNotFoundError: - logging.warning(f"File not found: {old_name}") - -# %% [markdown] -# Over 400,000 protein groups were only identified once (as exactly this group). - -# %% -vaep.pandas.counts_with_proportion(pd.Series(c)) # Most proteinGroups are unique - -# %% [markdown] -# ## Count genes -# Genes sets could be used to identify common features. -# -# > The assignment of isoforms to one proteinGroup or another might be volatile. -# > A single (unique) peptide could lead to different assignments. -# > Imputation on the evidence level could be a way to alleviate this problem -# -# - If genes set are not unique for a single run, one would have to decide which to take - -# %% -gene_counter = vaep.io.data_objects.GeneCounter(FNAME_C_GENES, overwrite=OVERWRITE) - -if not gene_counter.dumps: - # empty dict, replace - gene_counter.dumps = dict(protein_groups_counter.dumps) # prot proteinGroups files to GeneCounter -pg_dumps = list(gene_counter.dumps.values()) - -c_genes = gene_counter.sum_over_files(folders=pg_dumps) - -c_genes = pd.Series(c_genes) -vaep.pandas.counts_with_proportion(c_genes) # Most proteinGroups are unique - -# %% [markdown] Collapsed="false" -# ## Theoretial Peptides from used fasta-file -# -# > `01_explore_FASTA.ipynb` (formely `misc_FASTA_tryptic_digest.ipynb`) - -# %% [markdown] -# diff --git a/project/erda_03_training_data.ipynb b/project/erda_03_training_data.ipynb deleted file mode 100644 index 1047d6ec9..000000000 --- a/project/erda_03_training_data.ipynb +++ /dev/null @@ -1,396 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Build a set of training data\n", - "\n", - "Use a set of (most) common peptides to create inital data sets\n", - "\n", - "- based on `Counter` over all outputs from search (here: MaxQuant)\n", - " - keep based on threshold `FEAT_COMPLETNESS_CUTOFF` possible features\n", - " - option: select samples based on `YEARS` (e.g. due constrain by a batch of strains)\n", - " - collect in wide format data from output files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from functools import partial\n", - "from pathlib import Path\n", - "import logging\n", - "import multiprocessing\n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "from tqdm.notebook import tqdm_notebook\n", - "\n", - "import vaep\n", - "\n", - "import config\n", - "from config.training_data import peptides as cfg\n", - "\n", - "\n", - "def join_as_str(seq):\n", - " ret = \"_\".join(str(x) for x in seq)\n", - " return ret" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setup" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "incorrectly_encoded_metadata": "[tag=parameters]", - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "RANDOM_SEED: int = 42 # Random seed for reproducibility\n", - "FEAT_COMPLETNESS_CUTOFF = 0.25 # Minimal proportion of samples which have to share a feature\n", - "SAMPLE_COL = 'Sample ID'\n", - "OUT_FOLDER = 'data/selected/'\n", - "FN_ID_OLD_NEW: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Select a specific config file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "# options = ['peptides', 'evidence', 'proteinGroups']\n", - "# from config.training_data import evidence as cfg\n", - "# from config.training_data import proteinGroups as cfg\n", - "\n", - "cfg_dict = {k: getattr(cfg, k) for k in dir(cfg) if not k.startswith('_')}\n", - "cfg_dict" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Set defaults from file (allows to potentially overwrite parameters)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# normal structure of config.py files\n", - "NAME = cfg.NAME\n", - "BASE_NAME = cfg.BASE_NAME\n", - "\n", - "TYPES_DUMP = cfg.TYPES_DUMP\n", - "TYPES_COUNT = cfg.TYPES_COUNT\n", - "\n", - "IDX_COLS_LONG = cfg.IDX_COLS_LONG\n", - "\n", - "LOAD_DUMP = cfg.LOAD_DUMP\n", - "\n", - "CounterClass = cfg.CounterClass\n", - "FNAME_COUNTER = cfg.FNAME_COUNTER" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "out_folder = Path(OUT_FOLDER) / cfg.NAME\n", - "out_folder.mkdir(exist_ok=True, parents=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Selected IDs\n", - "\n", - "- currently only `Sample ID` is used\n", - "- path are to `.raw` raw files, not the output folder (could be changed)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_ids = pd.read_csv(FN_ID_OLD_NEW)\n", - "df_ids" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Counter" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "counter = CounterClass(FNAME_COUNTER)\n", - "counts = counter.get_df_counts()\n", - "counts" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "if TYPES_COUNT:\n", - " counts = counts.convert_dtypes().astype({'Charge': int})\n", - "mask = counts['proportion'] >= FEAT_COMPLETNESS_CUTOFF\n", - "counts.loc[mask]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Based on selected samples, retain features that potentially could be in the subset\n", - "\n", - "- if 1000 samples are selected, and given at treshold of 25%, one would need at least 250 observations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "treshold_counts = int(len(df_ids) * FEAT_COMPLETNESS_CUTOFF)\n", - "mask = counts['counts'] >= treshold_counts\n", - "counts.loc[mask]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "IDX_selected = counts.loc[mask].set_index(cfg.IDX_COLS_LONG[1:]).index\n", - "if len(cfg.IDX_COLS_LONG[1:]) > 1:\n", - " IDX_selected = IDX_selected.map(join_as_str)\n", - "IDX_selected" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Select Dumps" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "selected_dumps = df_ids[\"Sample ID\"]\n", - "selected_dumps = {k: counter.dumps[k] for k in selected_dumps}\n", - "selected_dumps = list(selected_dumps.items())\n", - "print(f\"Selected # {len(selected_dumps):,d} dumps.\")\n", - "selected_dumps[:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Collect in parallel" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def load_fct(path):\n", - " s = (\n", - " pd.read_csv(path, index_col=cfg.IDX_COLS_LONG[1:], usecols=[*cfg.IDX_COLS_LONG[1:], \"Intensity\"])\n", - " .squeeze()\n", - " .astype(pd.Int64Dtype())\n", - " )\n", - " if len(cfg.IDX_COLS_LONG[1:]) > 1:\n", - " s.index = s.index.map(join_as_str)\n", - "\n", - " return s\n", - "\n", - "\n", - "load_fct(selected_dumps[0][-1])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def collect(folders, index, load_fct):\n", - " current = multiprocessing.current_process()\n", - " i = current._identity[0] % N_WORKERS + 1\n", - " print(\" \", end=\"\", flush=True)\n", - "\n", - " failed = []\n", - " all = pd.DataFrame(index=index)\n", - "\n", - " with tqdm_notebook(total=len(folders), position=i) as pbar:\n", - " for id, path in folders:\n", - " try:\n", - " s = load_fct(path)\n", - " s.name = id\n", - " all = all.join(s, how='left')\n", - " except FileNotFoundError:\n", - " logging.warning(f\"File not found: {path}\")\n", - " failed.append((id, path))\n", - " except pd.errors.EmptyDataError:\n", - " logging.warning(f\"Empty file: {path}\")\n", - " failed.append((id, path))\n", - " pbar.update(1)\n", - "\n", - " return all" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Collect intensities in parallel" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "all = None # free memory\n", - "\n", - "collect_intensities = partial(collect, index=IDX_selected, load_fct=load_fct)\n", - "\n", - "N_WORKERS = 8\n", - "\n", - "with multiprocessing.Pool(N_WORKERS) as p:\n", - " all = list(\n", - " tqdm_notebook(\n", - " p.imap(collect_intensities,\n", - " np.array_split(selected_dumps, N_WORKERS)),\n", - " total=N_WORKERS,\n", - " )\n", - " )\n", - "\n", - "all = pd.concat(all, axis=1)\n", - "all" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "all.memory_usage(deep=True).sum() / (2**20)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# all = pd.read_pickle('data/selected/proteinGroups/intensities_wide_selected_N00100_M07444.pkl')\n", - "all = all.rename(df_ids.set_index(\"Sample ID\")['new_sample_id'], axis=1)\n", - "all.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "fname = out_folder / config.insert_shape(all, 'intensities_wide_selected{}.pkl')\n", - "all.to_pickle(fname)\n", - "fname" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "all.to_csv(fname.with_suffix('.csv'), chunksize=1_000)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Samples as rows, feature columns as columns\n", - "\n", - "- can fail due to memory -> next notebook" - ] - } - ], - "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.8.15" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/erda_03_training_data.py b/project/erda_03_training_data.py deleted file mode 100644 index 09bfdcc41..000000000 --- a/project/erda_03_training_data.py +++ /dev/null @@ -1,232 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# %% [markdown] -# # Build a set of training data -# -# Use a set of (most) common peptides to create inital data sets -# -# - based on `Counter` over all outputs from search (here: MaxQuant) -# - keep based on threshold `FEAT_COMPLETNESS_CUTOFF` possible features -# - option: select samples based on `YEARS` (e.g. due constrain by a batch of strains) -# - collect in wide format data from output files - -# %% -from functools import partial -from pathlib import Path -import logging -import multiprocessing - -import numpy as np -import pandas as pd - -from tqdm.notebook import tqdm_notebook - -import vaep - -import config -from config.training_data import peptides as cfg - - -def join_as_str(seq): - ret = "_".join(str(x) for x in seq) - return ret - - -# %% [markdown] -# ## Setup - -# %% [tag=parameters] -RANDOM_SEED: int = 42 # Random seed for reproducibility -FEAT_COMPLETNESS_CUTOFF = 0.25 # Minimal proportion of samples which have to share a feature -SAMPLE_COL = 'Sample ID' -OUT_FOLDER = 'data/selected/' -FN_ID_OLD_NEW: str = 'data/rename/selected_old_new_id_mapping.csv' # selected samples with pride and original id - - -# %% [markdown] -# Select a specific config file - -# %% -# options = ['peptides', 'evidence', 'proteinGroups'] -# from config.training_data import evidence as cfg -# from config.training_data import proteinGroups as cfg - -cfg_dict = {k: getattr(cfg, k) for k in dir(cfg) if not k.startswith('_')} -cfg_dict - - -# %% [markdown] -# Set defaults from file (allows to potentially overwrite parameters) - -# %% -# normal structure of config.py files -NAME = cfg.NAME -BASE_NAME = cfg.BASE_NAME - -TYPES_DUMP = cfg.TYPES_DUMP -TYPES_COUNT = cfg.TYPES_COUNT - -IDX_COLS_LONG = cfg.IDX_COLS_LONG - -LOAD_DUMP = cfg.LOAD_DUMP - -CounterClass = cfg.CounterClass -FNAME_COUNTER = cfg.FNAME_COUNTER - -# %% -out_folder = Path(OUT_FOLDER) / cfg.NAME -out_folder.mkdir(exist_ok=True, parents=True) - - -# %% [markdown] -# ## Selected IDs -# -# - currently only `Sample ID` is used -# - path are to `.raw` raw files, not the output folder (could be changed) - -# %% -df_ids = pd.read_csv(FN_ID_OLD_NEW) -df_ids - -# %% [markdown] -# ## Counter - -# %% -counter = CounterClass(FNAME_COUNTER) -counts = counter.get_df_counts() -counts - -# %% -if TYPES_COUNT: - counts = counts.convert_dtypes().astype({'Charge': int}) -mask = counts['proportion'] >= FEAT_COMPLETNESS_CUTOFF -counts.loc[mask] - -# %% [markdown] -# Based on selected samples, retain features that potentially could be in the subset -# -# - if 1000 samples are selected, and given at treshold of 25%, one would need at least 250 observations - -# %% -treshold_counts = int(len(df_ids) * FEAT_COMPLETNESS_CUTOFF) -mask = counts['counts'] >= treshold_counts -counts.loc[mask] - -# %% -IDX_selected = counts.loc[mask].set_index(cfg.IDX_COLS_LONG[1:]).index -if len(cfg.IDX_COLS_LONG[1:]) > 1: - IDX_selected = IDX_selected.map(join_as_str) -IDX_selected - -# %% [markdown] -# ## Select Dumps - -# %% -selected_dumps = df_ids["Sample ID"] -selected_dumps = {k: counter.dumps[k] for k in selected_dumps} -selected_dumps = list(selected_dumps.items()) -print(f"Selected # {len(selected_dumps):,d} dumps.") -selected_dumps[:10] - - -# %% [markdown] -# ## Collect in parallel - -# %% -def load_fct(path): - s = ( - pd.read_csv(path, index_col=cfg.IDX_COLS_LONG[1:], usecols=[*cfg.IDX_COLS_LONG[1:], "Intensity"]) - .squeeze() - .astype(pd.Int64Dtype()) - ) - if len(cfg.IDX_COLS_LONG[1:]) > 1: - s.index = s.index.map(join_as_str) - - return s - - -load_fct(selected_dumps[0][-1]) - - -# %% -def collect(folders, index, load_fct): - current = multiprocessing.current_process() - i = current._identity[0] % N_WORKERS + 1 - print(" ", end="", flush=True) - - failed = [] - all = pd.DataFrame(index=index) - - with tqdm_notebook(total=len(folders), position=i) as pbar: - for id, path in folders: - try: - s = load_fct(path) - s.name = id - all = all.join(s, how='left') - except FileNotFoundError: - logging.warning(f"File not found: {path}") - failed.append((id, path)) - except pd.errors.EmptyDataError: - logging.warning(f"Empty file: {path}") - failed.append((id, path)) - pbar.update(1) - - return all - - -# %% [markdown] -# ## Collect intensities in parallel - -# %% -all = None # free memory - -collect_intensities = partial(collect, index=IDX_selected, load_fct=load_fct) - -N_WORKERS = 8 - -with multiprocessing.Pool(N_WORKERS) as p: - all = list( - tqdm_notebook( - p.imap(collect_intensities, - np.array_split(selected_dumps, N_WORKERS)), - total=N_WORKERS, - ) - ) - -all = pd.concat(all, axis=1) -all - -# %% -all.memory_usage(deep=True).sum() / (2**20) - -# %% -# all = pd.read_pickle('data/selected/proteinGroups/intensities_wide_selected_N00100_M07444.pkl') -all = all.rename(df_ids.set_index("Sample ID")['new_sample_id'], axis=1) -all.head() - -# %% -# %%time -fname = out_folder / config.insert_shape(all, 'intensities_wide_selected{}.pkl') -all.to_pickle(fname) -fname - -# %% -# %%time -all.to_csv(fname.with_suffix('.csv'), chunksize=1_000) - -# %% [markdown] -# Samples as rows, feature columns as columns -# -# - can fail due to memory -> next notebook diff --git a/project/erda_04_transpose_file.ipynb b/project/erda_04_transpose_file.ipynb deleted file mode 100644 index a8e1c6f1d..000000000 --- a/project/erda_04_transpose_file.ipynb +++ /dev/null @@ -1,286 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "8460a0bd-e679-4d04-ac84-ab0998900099", - "metadata": {}, - "source": [ - "# Transpose file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "76501fbd-b7fe-4010-8137-bb4cba2bee99", - "metadata": {}, - "outputs": [], - "source": [ - "from pathlib import Path\n", - "import pandas as pd\n", - "\n", - "import vaep\n", - "\n", - "import config" - ] - }, - { - "cell_type": "markdown", - "id": "23dabaa3-4ffb-41ff-8931-92f0684dd617", - "metadata": {}, - "source": [ - "Paramters" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "98952a84-2e8b-4416-a079-1ad9c755cfe5", - "metadata": {}, - "outputs": [], - "source": [ - "# out_folder = Path('data/selected/proteinGroups')\n", - "# fname = out_folder / 'intensities_wide_selected_N04550_M07444.pkl'\n", - "\n", - "# out_folder = Path('data/selected/peptides')\n", - "# fname = out_folder / 'intensities_wide_selected_N42881_M07441.pkl'\n", - "\n", - "out_folder = Path('data/selected/evidence')\n", - "fname = out_folder / 'intensities_wide_selected_N49560_M07444.pkl'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ffe6a395-66a7-4b50-9f58-d58746666122", - "metadata": {}, - "outputs": [], - "source": [ - "def get_template(fname, split='_N'):\n", - " ext = fname.suffix\n", - " stem = fname.stem.split(split)[0]\n", - " return f\"{stem}{{}}{ext}\"\n", - "\n", - "\n", - "def memory_usage_in_mb(df):\n", - " return df.memory_usage(deep=True).sum() / (2**20)\n", - "\n", - "\n", - "template = get_template(fname)\n", - "template" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d4abfa6d-7398-4c1f-8dac-bbf055931b70", - "metadata": {}, - "outputs": [], - "source": [ - "files_out = {}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "771acfc5-f9d1-4aaf-8f3c-a5b2298ab559", - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "df = pd.read_pickle(fname)\n", - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1f2d73d4-96f3-4883-89a2-4085433a71c4", - "metadata": {}, - "outputs": [], - "source": [ - "df.memory_usage(deep=True).sum() / (2**20)" - ] - }, - { - "cell_type": "markdown", - "id": "eb613ede-5949-4c04-a5c5-a3e9b112de0d", - "metadata": {}, - "source": [ - "Here reading the csv file is slightly faster and consumes less memory.\n", - "\n", - "- dtype: `float64` -> missing values as `np.nan`\n", - "- but: saving to csv will be larger." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2ac14afc-7e94-45b3-b1c4-008ca8db5f00", - "metadata": {}, - "outputs": [], - "source": [ - "# %%time\n", - "# df = pd.read_csv(fname.with_suffix('.csv'), index_col=0)\n", - "# df.memory_usage(deep=True).sum() / (2**20)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "632fa73a-1db4-410f-b513-2f80b549948a", - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "count_samples = df.notna().sum()\n", - "\n", - "fname = out_folder / 'count_samples.json'\n", - "count_samples.to_json(fname)\n", - "\n", - "vaep.plotting.make_large_descriptors(size='medium')\n", - "\n", - "ax = count_samples.sort_values().plot(rot=90, ylabel='observations')\n", - "ax.yaxis.set_major_formatter(\"{x:,.0f}\")\n", - "vaep.savefig(ax.get_figure(), fname)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "57eca231-2bfe-4939-bc93-3b31836a0379", - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "df = df.T\n", - "df.memory_usage(deep=True).sum() / (2**20)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "11e30e15-d802-41fb-9cba-7e08d91eaf9d", - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "fname = out_folder / config.insert_shape(df, template=template)\n", - "files_out[fname.name] = fname.as_posix()\n", - "df.to_pickle(fname)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cc4f2a51-0c7e-4394-bb34-eda4146844ff", - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "fname = fname.with_suffix('.csv')\n", - "files_out[fname.name] = fname.as_posix()\n", - "df.to_csv(fname, chunksize=1_000)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3bc9250b-9a0c-4a44-b375-e1c06d9881b3", - "metadata": {}, - "outputs": [], - "source": [ - "count_features = df.notna().sum()\n", - "fname = out_folder / 'count_feat.json'\n", - "count_features.to_json(fname)\n", - "\n", - "ax = count_features.sort_values().plot(rot=90, ylabel='observations')\n", - "ax.yaxis.set_major_formatter(\"{x:,.0f}\")\n", - "vaep.savefig(ax.get_figure(), fname)" - ] - }, - { - "cell_type": "markdown", - "id": "448678a9-f239-4fc0-89a5-afbf6fea62f8", - "metadata": {}, - "source": [ - "## Present abesent pattern" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "02f74eb0-2ffd-4014-9d52-583f33ba4e29", - "metadata": {}, - "outputs": [], - "source": [ - "df = df.notna().astype(pd.Int8Dtype())\n", - "df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "017e027a-6503-4033-947d-d306a08e7a27", - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "fname = out_folder / config.insert_shape(df, 'absent_0_present_1_selected{}.pkl')\n", - "\n", - "files_out[fname.name] = fname.as_posix()\n", - "df.to_pickle(fname)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d3fa48d3-cc66-4f90-8081-c42cced74d72", - "metadata": {}, - "outputs": [], - "source": [ - "files_outfname = fname.with_suffix('.csv')\n", - "files_out[fname.name] = fname.as_posix()\n", - "df.replace(0, pd.NA).to_csv(fname.with_suffix('.csv'), chunksize=1_000)" - ] - }, - { - "cell_type": "markdown", - "id": "4b565b50-13fd-48ac-a0c2-c52ce31d10a5", - "metadata": {}, - "source": [ - "## Files written" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8cd67887-c1b8-4718-910c-7d0871f71f71", - "metadata": {}, - "outputs": [], - "source": [ - "files_out" - ] - } - ], - "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.8.15" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/erda_04_transpose_file.py b/project/erda_04_transpose_file.py deleted file mode 100644 index e26aa156e..000000000 --- a/project/erda_04_transpose_file.py +++ /dev/null @@ -1,138 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# %% [markdown] -# # Transpose file - -# %% -from pathlib import Path -import pandas as pd - -import vaep - -import config - -# %% [markdown] -# Paramters - -# %% -# out_folder = Path('data/selected/proteinGroups') -# fname = out_folder / 'intensities_wide_selected_N04550_M07444.pkl' - -# out_folder = Path('data/selected/peptides') -# fname = out_folder / 'intensities_wide_selected_N42881_M07441.pkl' - -out_folder = Path('data/selected/evidence') -fname = out_folder / 'intensities_wide_selected_N49560_M07444.pkl' - - -# %% -def get_template(fname, split='_N'): - ext = fname.suffix - stem = fname.stem.split(split)[0] - return f"{stem}{{}}{ext}" - - -def memory_usage_in_mb(df): - return df.memory_usage(deep=True).sum() / (2**20) - - -template = get_template(fname) -template - -# %% -files_out = {} - -# %% -# %%time -df = pd.read_pickle(fname) -df.head() - -# %% -df.memory_usage(deep=True).sum() / (2**20) - -# %% [markdown] -# Here reading the csv file is slightly faster and consumes less memory. -# -# - dtype: `float64` -> missing values as `np.nan` -# - but: saving to csv will be larger. - -# %% -# # %%time -# df = pd.read_csv(fname.with_suffix('.csv'), index_col=0) -# df.memory_usage(deep=True).sum() / (2**20) - -# %% -# %%time -count_samples = df.notna().sum() - -fname = out_folder / 'count_samples.json' -count_samples.to_json(fname) - -vaep.plotting.make_large_descriptors(size='medium') - -ax = count_samples.sort_values().plot(rot=90, ylabel='observations') -ax.yaxis.set_major_formatter("{x:,.0f}") -vaep.savefig(ax.get_figure(), fname) - -# %% -# %%time -df = df.T -df.memory_usage(deep=True).sum() / (2**20) - -# %% -# %%time -fname = out_folder / config.insert_shape(df, template=template) -files_out[fname.name] = fname.as_posix() -df.to_pickle(fname) - -# %% -# %%time -fname = fname.with_suffix('.csv') -files_out[fname.name] = fname.as_posix() -df.to_csv(fname, chunksize=1_000) - -# %% -count_features = df.notna().sum() -fname = out_folder / 'count_feat.json' -count_features.to_json(fname) - -ax = count_features.sort_values().plot(rot=90, ylabel='observations') -ax.yaxis.set_major_formatter("{x:,.0f}") -vaep.savefig(ax.get_figure(), fname) - -# %% [markdown] -# ## Present abesent pattern - -# %% -df = df.notna().astype(pd.Int8Dtype()) -df - -# %% -# %%time -fname = out_folder / config.insert_shape(df, 'absent_0_present_1_selected{}.pkl') - -files_out[fname.name] = fname.as_posix() -df.to_pickle(fname) - -# %% -files_outfname = fname.with_suffix('.csv') -files_out[fname.name] = fname.as_posix() -df.replace(0, pd.NA).to_csv(fname.with_suffix('.csv'), chunksize=1_000) - -# %% [markdown] -# ## Files written - -# %% -files_out diff --git a/project/erda_05_parse_paramter_files.ipynb b/project/erda_05_parse_paramter_files.ipynb deleted file mode 100644 index ba59184a3..000000000 --- a/project/erda_05_parse_paramter_files.ipynb +++ /dev/null @@ -1,554 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "368f6451-9bec-4ca6-9921-c5ab69c23153", - "metadata": {}, - "source": [ - "# Parse parameter files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3c3a8745-20e5-4353-a3d6-950a3bc1dd6c", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "from pprint import pprint\n", - "import collections\n", - "from pathlib import Path\n", - "from tqdm.notebook import tqdm\n", - "\n", - "import pandas as pd" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "92c20a10-a814-4a50-8186-d05fa1e14498", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "import logging\n", - "\n", - "import xml.etree.ElementTree as ET\n", - "\n", - "logger = logging.getLogger()\n", - "\n", - "test_file = 'data/mqpar_example.xml'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e1645c86-7799-46db-92cd-cd5157cd11d8", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "def extend_tuple(t, target_length: int):\n", - " if not isinstance(t, tuple):\n", - " raise TypeError(\n", - " f\"Wrong type provided. Expected tuple, got {type(t)} : {t!r}\")\n", - " if len(t) > target_length:\n", - " raise ValueError(\n", - " f\"Tuple is too long (got {len(t)}, expected {target_length}: {t!r}\")\n", - " return t + (None,) * (target_length - len(t))\n", - "# extend_tuple(\"test\", 4)\n", - "# extend_tuple(('k1', 'k2'), 1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4341046b-13d2-49c5-924c-a73fd9f366d1", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "def extend_tuples_with_none(list_of_tuples, target_length):\n", - " extended_tuples = []\n", - " for tuple_ in list_of_tuples:\n", - " # if len(tuple_) > target_length:\n", - " # raise ValueError(f\"tuple is too long: {len(tuple_)}\")\n", - " extended_tuple = extend_tuple(tuple_, target_length)\n", - " extended_tuples.append(extended_tuple)\n", - " return extended_tuples\n", - "\n", - "\n", - "list_of_tuples = [(1, 2), (3, 4, 5), (6,)]\n", - "extend_tuples_with_none(list_of_tuples, 3)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8691214b-65a1-4c27-92d7-f927dbac61bf", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "\n", - "\n", - "def add_record(data, tag, record):\n", - " if tag in data:\n", - " if isinstance(data[tag], list):\n", - " data[tag].append(record)\n", - " else:\n", - " data[tag] = [data[tag], record]\n", - " else:\n", - " data[tag] = record\n", - " return data\n", - "\n", - "\n", - "def read_xml_record(element):\n", - " data = dict()\n", - " for child in element:\n", - " if len(child) > 1 and child.tag:\n", - " # if there is a list, process each element one by one\n", - " # either nested or a plain text\n", - " data[child.tag] = [add_record(dict(), tag=child.tag, record=read_xml_record(child) if not (\n", - " child.text and child.text.strip()) else child.text.strip()) for child in child]\n", - " elif child.text and child.text.strip():\n", - " # just plain text record\n", - " data = add_record(data=data, tag=child.tag,\n", - " record=child.text.strip())\n", - " else:\n", - " record = read_xml_record(child)\n", - " data = add_record(data, child.tag, record)\n", - " if not data:\n", - " # empty strings and None are normalzied to None\n", - " return None\n", - " return data\n", - "\n", - "\n", - "tree = ET.parse(test_file)\n", - "root = tree.getroot()\n", - "\n", - "record_example = read_xml_record(root)\n", - "record_example" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "10f3103a-8133-4d01-9c6a-efcc75d85295", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "\n", - "\n", - "def flatten_dict_of_dicts(d: dict, parent_key: str = '') -> dict:\n", - " \"\"\"Build tuples for nested dictionaries for use as `pandas.MultiIndex`.\n", - "\n", - " Parameters\n", - " ----------\n", - " d : dict\n", - " Nested dictionary for which all keys are flattened to tuples.\n", - " parent_key : str, optional\n", - " Outer key (used for recursion), by default ''\n", - "\n", - " Returns\n", - " -------\n", - " dict\n", - " Flattend dictionary with tuple keys: {(outer_key, ..., inner_key) : value}\n", - " \"\"\"\n", - " # simplified and adapted from: https://stackoverflow.com/a/6027615/9684872\n", - " items = []\n", - " for k, v in d.items():\n", - " new_key = parent_key + (k,) if parent_key else (k,)\n", - " if isinstance(v, collections.abc.MutableMapping):\n", - " items.extend(flatten_dict_of_dicts(v, parent_key=new_key))\n", - " elif isinstance(v, list):\n", - " for item in v:\n", - " if isinstance(item, collections.abc.MutableMapping):\n", - " items.extend(flatten_dict_of_dicts(\n", - " item, parent_key=new_key))\n", - " elif isinstance(item, str):\n", - " items.append((new_key, item))\n", - " else:\n", - " raise ValueError(f\"Unknown item: {item:r}\")\n", - " else:\n", - " items.append((new_key, v))\n", - " return items\n", - "\n", - "\n", - "case_1 = {'k': 'v'}\n", - "case_2 = {'k1': {'k2': 'v1', 'k3': 'v2'}}\n", - "case_3 = {'k1': {'k2': [{'k4': 'v1'}, {'k4': 'v2'}]}}\n", - "case_4 = {'k1': [{'k2': {'k4': 'v1', 'k5': 'v2'}},\n", - " {'k2': {'k4': 'v1', 'k5': 'v2'}}]}\n", - "case_5 = {'restrictMods': [{'string': 'Oxidation (M)'},\n", - " {'string': 'Acetyl (Protein N-term)'}]}\n", - "case_6 = {'variableModifications': {\n", - " 'string': ['Oxidation (M)',\n", - " 'Acetyl (Protein N-term)']}}\n", - "\n", - "test_cases = [case_1, case_2, case_3, case_4, case_5, case_6]\n", - "\n", - "for case in (test_cases):\n", - " pprint(flatten_dict_of_dicts(case))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c8e19d55-d012-44be-8869-0271e16a7093", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "entries = list()\n", - "for case in test_cases:\n", - " entries.extend(flatten_dict_of_dicts(case))\n", - "[(extend_tuple(k, 4), v) for (k, v) in entries]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "76092ebb-e31e-4bf2-b350-090c51d1e1bc", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "def build_Series_from_records(records, index_length=4):\n", - " records = flatten_dict_of_dicts(records)\n", - " idx = pd.MultiIndex.from_tuples(\n", - " (extend_tuple(k, index_length) for (k, v) in records))\n", - " return pd.Series((v for (k, v) in records), index=idx)\n", - "\n", - "\n", - "tree = ET.parse(test_file)\n", - "root = tree.getroot()\n", - "\n", - "record_example = read_xml_record(root)\n", - "flattend = build_Series_from_records(record_example, 4)\n", - "flattend.to_frame('example')" - ] - }, - { - "cell_type": "markdown", - "id": "e63a712a-a6e8-46dc-befc-bc6a98a6a153", - "metadata": {}, - "source": [ - "## Parameters" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e718825e-428a-4d99-81e6-03cce50da2fc", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# folders to check\n", - "folder_w_params = Path('/home/jovyan/work/mqpar_files')\n", - "root = Path('/home/jovyan/work/')\n", - "dumped_folder = 'mq_out'\n", - "dumped_folder_names = 'mq_out_folder.txt'\n", - "# out\n", - "fname_out = 'data/all_parameter_files.csv'" - ] - }, - { - "cell_type": "markdown", - "id": "891ee5ec-03a2-4d66-845b-a2938c9018f7", - "metadata": {}, - "source": [ - "## Dump of some parameter files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fbdc4c32-9995-43ae-aff3-9b6358cf9ea2", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "def read_file(file, name, idx_levels=4) -> pd.Series:\n", - " tree = ET.parse(file)\n", - " root = tree.getroot()\n", - " record = read_xml_record(root)\n", - " s = build_Series_from_records(record, idx_levels)\n", - " s.name = name\n", - " return s" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c779378e-8b0c-440b-a43a-c1a10939cf8f", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_files_part_1 = list()\n", - "for file in tqdm(folder_w_params.iterdir()):\n", - " s_parameters = read_file(file, name=file.stem[6:])\n", - " parameter_files_part_1.append(s_parameters)\n", - "\n", - "parameter_files_part_1 = pd.concat(parameter_files_part_1, axis=1).T\n", - "parameter_files_part_1" - ] - }, - { - "cell_type": "markdown", - "id": "a5db69d3-89ed-4670-ae9a-d5e548e43106", - "metadata": {}, - "source": [ - "## Search for parameter files in output folders\n", - "\n", - "- read folders from dump (for stable execution on erda)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6dea94bd-dc1b-4e5b-ad99-0c6f1dc34682", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# # read as generator if file does not exist:\n", - "# folders = list(Path('/home/jovyan/work/mq_out').iterdir())\n", - "\n", - "root = Path('/home/jovyan/work/')\n", - "with open(root / dumped_folder_names) as f:\n", - " folders = list()\n", - " for line in f:\n", - " fpath = root / dumped_folder / line.strip()\n", - " folders.append(fpath)" - ] - }, - { - "cell_type": "markdown", - "id": "fd65f35b-7818-4275-961f-816aedfaa486", - "metadata": {}, - "source": [ - "read paramter files:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "32add481-89ba-4c22-b419-f025f98c2f2c", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_files_part_2 = list()\n", - "i = 0\n", - "for folder in tqdm(folders):\n", - " for file in folder.iterdir():\n", - " if file.suffix == '.xml':\n", - " s_parameters = read_file(file, file.parent.name)\n", - " parameter_files_part_2.append(s_parameters)\n", - " i += 1\n", - "\n", - "parameter_files_part_2 = pd.concat(parameter_files_part_2, axis=1).T\n", - "parameter_files_part_2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bd945d90-8416-4ddd-9b46-ab7e47ed1840", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "print(f\"Found {i} parameter files\")" - ] - }, - { - "cell_type": "markdown", - "id": "71cf0a35-0cf9-4fb1-9abc-08cad21d4fae", - "metadata": {}, - "source": [ - "## Combine both sets" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "985d4fab-49ad-45b7-ae2d-de66cbdae5a4", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_files = pd.concat([parameter_files_part_1, parameter_files_part_2])\n", - "# del parameter_files_part_1, parameter_files_part_2\n", - "parameter_files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "81944709-5e74-4067-ab4a-d20e2054ecd0", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# 11066" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "48197990-124f-4abc-8c42-3b4982f3cd4b", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_files = parameter_files.infer_objects()\n", - "parameter_files.dtypes.value_counts()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4e0627e5-22c2-4b08-be5b-b57866b15d13", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_files.to_csv(fname_out)" - ] - }, - { - "cell_type": "markdown", - "id": "33bbf09d-6059-4abc-96d6-677f1dfb3eb5", - "metadata": {}, - "source": [ - "Read aggregated parameters dump" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d749fdc5-9f56-45ab-879c-1e01977e733a", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_files = pd.read_csv(fname_out, index_col=0, header=list(range(4)))\n", - "parameter_files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "858a7dbf-a5e3-47d3-98e4-f130306cfbf0", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_files.dtypes.value_counts()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "88c9f10e-5a4d-4653-b6f8-cfe6152f1b5a", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_files.loc[:, parameter_files.dtypes == 'object']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9a6c70d1-c5eb-49ab-82f1-fe919a8b60e7", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_files['fastaFiles']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "319e99f2-9236-406c-b95a-493864dcbf03", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_files.droplevel(-1, axis=1)['fastaFiles']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1f1a185a-b0e8-40bd-b35c-4c9be49099f7", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "parameter_files.columns.to_list()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5319b502-58ac-4a5c-94dc-4c9915f302ee", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "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.10.12" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/erda_05_parse_paramter_files.py b/project/erda_05_parse_paramter_files.py deleted file mode 100644 index eb108d4f5..000000000 --- a/project/erda_05_parse_paramter_files.py +++ /dev/null @@ -1,290 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: Python 3 (ipykernel) -# language: python -# name: python3 -# --- - -# %% [markdown] -# # Parse parameter files - -# %% -from pprint import pprint -import collections -from pathlib import Path -from tqdm.notebook import tqdm - -import pandas as pd - -# %% -import logging - -import xml.etree.ElementTree as ET - -logger = logging.getLogger() - -test_file = 'data/mqpar_example.xml' - - -# %% -def extend_tuple(t, target_length: int): - if not isinstance(t, tuple): - raise TypeError( - f"Wrong type provided. Expected tuple, got {type(t)} : {t!r}") - if len(t) > target_length: - raise ValueError( - f"Tuple is too long (got {len(t)}, expected {target_length}: {t!r}") - return t + (None,) * (target_length - len(t)) -# extend_tuple("test", 4) -# extend_tuple(('k1', 'k2'), 1) - - -# %% -def extend_tuples_with_none(list_of_tuples, target_length): - extended_tuples = [] - for tuple_ in list_of_tuples: - # if len(tuple_) > target_length: - # raise ValueError(f"tuple is too long: {len(tuple_)}") - extended_tuple = extend_tuple(tuple_, target_length) - extended_tuples.append(extended_tuple) - return extended_tuples - - -list_of_tuples = [(1, 2), (3, 4, 5), (6,)] -extend_tuples_with_none(list_of_tuples, 3) - -# %% - - -def add_record(data, tag, record): - if tag in data: - if isinstance(data[tag], list): - data[tag].append(record) - else: - data[tag] = [data[tag], record] - else: - data[tag] = record - return data - - -def read_xml_record(element): - data = dict() - for child in element: - if len(child) > 1 and child.tag: - # if there is a list, process each element one by one - # either nested or a plain text - data[child.tag] = [add_record(dict(), tag=child.tag, record=read_xml_record(child) if not ( - child.text and child.text.strip()) else child.text.strip()) for child in child] - elif child.text and child.text.strip(): - # just plain text record - data = add_record(data=data, tag=child.tag, - record=child.text.strip()) - else: - record = read_xml_record(child) - data = add_record(data, child.tag, record) - if not data: - # empty strings and None are normalzied to None - return None - return data - - -tree = ET.parse(test_file) -root = tree.getroot() - -record_example = read_xml_record(root) -record_example - -# %% - - -def flatten_dict_of_dicts(d: dict, parent_key: str = '') -> dict: - """Build tuples for nested dictionaries for use as `pandas.MultiIndex`. - - Parameters - ---------- - d : dict - Nested dictionary for which all keys are flattened to tuples. - parent_key : str, optional - Outer key (used for recursion), by default '' - - Returns - ------- - dict - Flattend dictionary with tuple keys: {(outer_key, ..., inner_key) : value} - """ - # simplified and adapted from: https://stackoverflow.com/a/6027615/9684872 - items = [] - for k, v in d.items(): - new_key = parent_key + (k,) if parent_key else (k,) - if isinstance(v, collections.abc.MutableMapping): - items.extend(flatten_dict_of_dicts(v, parent_key=new_key)) - elif isinstance(v, list): - for item in v: - if isinstance(item, collections.abc.MutableMapping): - items.extend(flatten_dict_of_dicts( - item, parent_key=new_key)) - elif isinstance(item, str): - items.append((new_key, item)) - else: - raise ValueError(f"Unknown item: {item:r}") - else: - items.append((new_key, v)) - return items - - -case_1 = {'k': 'v'} -case_2 = {'k1': {'k2': 'v1', 'k3': 'v2'}} -case_3 = {'k1': {'k2': [{'k4': 'v1'}, {'k4': 'v2'}]}} -case_4 = {'k1': [{'k2': {'k4': 'v1', 'k5': 'v2'}}, - {'k2': {'k4': 'v1', 'k5': 'v2'}}]} -case_5 = {'restrictMods': [{'string': 'Oxidation (M)'}, - {'string': 'Acetyl (Protein N-term)'}]} -case_6 = {'variableModifications': { - 'string': ['Oxidation (M)', - 'Acetyl (Protein N-term)']}} - -test_cases = [case_1, case_2, case_3, case_4, case_5, case_6] - -for case in (test_cases): - pprint(flatten_dict_of_dicts(case)) - -# %% -entries = list() -for case in test_cases: - entries.extend(flatten_dict_of_dicts(case)) -[(extend_tuple(k, 4), v) for (k, v) in entries] - - -# %% -def build_Series_from_records(records, index_length=4): - records = flatten_dict_of_dicts(records) - idx = pd.MultiIndex.from_tuples( - (extend_tuple(k, index_length) for (k, v) in records)) - return pd.Series((v for (k, v) in records), index=idx) - - -tree = ET.parse(test_file) -root = tree.getroot() - -record_example = read_xml_record(root) -flattend = build_Series_from_records(record_example, 4) -flattend.to_frame('example') - -# %% [markdown] -# ## Parameters - -# %% -# folders to check -folder_w_params = Path('/home/jovyan/work/mqpar_files') -root = Path('/home/jovyan/work/') -dumped_folder = 'mq_out' -dumped_folder_names = 'mq_out_folder.txt' -# out -fname_out = 'data/all_parameter_files.csv' - - -# %% [markdown] -# ## Dump of some parameter files - -# %% -def read_file(file, name, idx_levels=4) -> pd.Series: - tree = ET.parse(file) - root = tree.getroot() - record = read_xml_record(root) - s = build_Series_from_records(record, idx_levels) - s.name = name - return s - - -# %% -parameter_files_part_1 = list() -for file in tqdm(folder_w_params.iterdir()): - s_parameters = read_file(file, name=file.stem[6:]) - parameter_files_part_1.append(s_parameters) - -parameter_files_part_1 = pd.concat(parameter_files_part_1, axis=1).T -parameter_files_part_1 - -# %% [markdown] -# ## Search for parameter files in output folders -# -# - read folders from dump (for stable execution on erda) - -# %% -# # read as generator if file does not exist: -# folders = list(Path('/home/jovyan/work/mq_out').iterdir()) - -root = Path('/home/jovyan/work/') -with open(root / dumped_folder_names) as f: - folders = list() - for line in f: - fpath = root / dumped_folder / line.strip() - folders.append(fpath) - -# %% [markdown] -# read paramter files: - -# %% -parameter_files_part_2 = list() -i = 0 -for folder in tqdm(folders): - for file in folder.iterdir(): - if file.suffix == '.xml': - s_parameters = read_file(file, file.parent.name) - parameter_files_part_2.append(s_parameters) - i += 1 - -parameter_files_part_2 = pd.concat(parameter_files_part_2, axis=1).T -parameter_files_part_2 - -# %% -print(f"Found {i} parameter files") - -# %% [markdown] -# ## Combine both sets - -# %% -parameter_files = pd.concat([parameter_files_part_1, parameter_files_part_2]) -# del parameter_files_part_1, parameter_files_part_2 -parameter_files - -# %% -# 11066 - -# %% -parameter_files = parameter_files.infer_objects() -parameter_files.dtypes.value_counts() - -# %% -parameter_files.to_csv(fname_out) - -# %% [markdown] -# Read aggregated parameters dump - -# %% -parameter_files = pd.read_csv(fname_out, index_col=0, header=list(range(4))) -parameter_files - -# %% -parameter_files.dtypes.value_counts() - -# %% -parameter_files.loc[:, parameter_files.dtypes == 'object'] - -# %% -parameter_files['fastaFiles'] - -# %% -parameter_files.droplevel(-1, axis=1)['fastaFiles'] - -# %% -parameter_files.columns.to_list() - -# %% diff --git a/project/erda_06_analyze_parameters.ipynb b/project/erda_06_analyze_parameters.ipynb deleted file mode 100644 index 9887c58b8..000000000 --- a/project/erda_06_analyze_parameters.ipynb +++ /dev/null @@ -1,153 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "8154dacf", - "metadata": {}, - "source": [ - "# Analyzse and rename dumped parameters" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ad32c7c1", - "metadata": {}, - "outputs": [], - "source": [ - "import vaep\n", - "import pandas as pd\n", - "\n", - "fname_mq_params = 'data/all_parameter_files.csv'\n", - "fname_id_mappings = 'data/rename/selected_old_new_id_mapping.csv'\n", - "\n", - "fname_out = 'data/selected_parameter_files.csv'\n", - "\n", - "parameter_files = pd.read_csv(fname_mq_params, index_col=0, header=list(range(4))\n", - " )\n", - "parameter_files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "09d029d6", - "metadata": {}, - "outputs": [], - "source": [ - "# thread experiments...\n", - "vaep.pandas.show_columns_with_variation(\n", - " parameter_files\n", - " .loc[parameter_files.index.duplicated(keep=False)])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "05f5fc43", - "metadata": {}, - "outputs": [], - "source": [ - "parameter_files = parameter_files.loc[~parameter_files.index.duplicated()]\n", - "parameter_files" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b92ac981", - "metadata": {}, - "outputs": [], - "source": [ - "id_mappings = pd.read_csv(fname_id_mappings, index_col=0, usecols=['Sample ID', 'new_sample_id'])\n", - "id_mappings.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "245e795a", - "metadata": {}, - "outputs": [], - "source": [ - "parameter_files.loc[id_mappings.index]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ef8ffc10", - "metadata": {}, - "outputs": [], - "source": [ - "sel = (parameter_files\n", - " .loc[id_mappings.index]\n", - " .drop('filePaths', axis=1)\n", - " .rename(id_mappings['new_sample_id']))\n", - "sel.to_csv(fname_out)\n", - "sel" - ] - }, - { - "cell_type": "markdown", - "id": "b1f69026", - "metadata": {}, - "source": [ - "-inf and + inf cannot be handled correctly (fullMinMz, fullMaxMz)\n", - "number of Threads differs as the setting was varied in the beginning (most runs used 4 threads)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6b5ae165", - "metadata": {}, - "outputs": [], - "source": [ - "sel_with_diffs = vaep.pandas.show_columns_with_variation(sel)\n", - "sel_with_diffs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "15f413d3", - "metadata": {}, - "outputs": [], - "source": [ - "sel_with_diffs.describe()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ee554c42", - "metadata": {}, - "outputs": [], - "source": [ - "sel[('numThreads', 'nan', 'nan', 'nan')].value_counts()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8dc29350", - "metadata": {}, - "outputs": [], - "source": [ - "# 388 columns are identical\n", - "sel.drop(sel_with_diffs.columns, axis=1\n", - " ).drop_duplicates()" - ] - } - ], - "metadata": { - "jupytext": { - "cell_metadata_filter": "-all", - "main_language": "python", - "notebook_metadata_filter": "-all" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/erda_06_analyze_parameters.py b/project/erda_06_analyze_parameters.py deleted file mode 100644 index e2449ae5d..000000000 --- a/project/erda_06_analyze_parameters.py +++ /dev/null @@ -1,59 +0,0 @@ -# %% [markdown] -# # Analyzse and rename dumped parameters - -# %% -import vaep -import pandas as pd - -fname_mq_params = 'data/all_parameter_files.csv' -fname_id_mappings = 'data/rename/selected_old_new_id_mapping.csv' - -fname_out = 'data/selected_parameter_files.csv' - -parameter_files = pd.read_csv(fname_mq_params, index_col=0, header=list(range(4)) - ) -parameter_files - -# %% -# thread experiments... -vaep.pandas.show_columns_with_variation( - parameter_files - .loc[parameter_files.index.duplicated(keep=False)]) - -# %% -parameter_files = parameter_files.loc[~parameter_files.index.duplicated()] -parameter_files - -# %% -id_mappings = pd.read_csv(fname_id_mappings, index_col=0, usecols=['Sample ID', 'new_sample_id']) -id_mappings.head() - -# %% -parameter_files.loc[id_mappings.index] - -# %% -sel = (parameter_files - .loc[id_mappings.index] - .drop('filePaths', axis=1) - .rename(id_mappings['new_sample_id'])) -sel.to_csv(fname_out) -sel - -# %% [markdown] -# -inf and + inf cannot be handled correctly (fullMinMz, fullMaxMz) -# number of Threads differs as the setting was varied in the beginning (most runs used 4 threads) - -# %% -sel_with_diffs = vaep.pandas.show_columns_with_variation(sel) -sel_with_diffs - -# %% -sel_with_diffs.describe() - -# %% -sel[('numThreads', 'nan', 'nan', 'nan')].value_counts() - -# %% -# 388 columns are identical -sel.drop(sel_with_diffs.columns, axis=1 - ).drop_duplicates() diff --git a/project/erda_12_explore_raw_MQ_data.ipynb b/project/erda_12_explore_raw_MQ_data.ipynb deleted file mode 100644 index d2ffa8b9a..000000000 --- a/project/erda_12_explore_raw_MQ_data.ipynb +++ /dev/null @@ -1,1634 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Explore MaxQuant (MQ) output files of single runs\n", - "\n", - "The `erda_03_training_data.ipynb` notebook does extract information to be used as training data.\n", - "File specific one could also use the retention time analysis to identify _valid_ co-occurring peptides to be use during training.\n", - "Potentially this preprocessing step can be used at inference time.\n", - "\n", - "This notebook contains some relevant analysis for a specific `txt` output-folder in the current project\n", - "\n", - "##### Analysis overview\n", - "\n", - "> Report for example data\n", - "\n", - "- relation between `peptides.txt` and `evidence.txt`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "import logging\n", - "import random\n", - "\n", - "import ipywidgets as widgets\n", - "\n", - "from numpy.testing import assert_almost_equal\n", - "from numpy import random\n", - "import pandas as pd\n", - "# pd.options.display.float_format = '{:,.1f}'.format\n", - "\n", - "import vaep.pandas\n", - "from vaep.pandas import length\n", - "from vaep.io.mq import FASTA_KEYS, MaxQuantOutput\n", - "from vaep.io import search_subfolders\n", - "import vaep.io.mq as mq\n", - "from vaep.io.mq import mq_col\n", - "\n", - "##### CONFIG #####\n", - "import config\n", - "from config import FOLDER_MQ_TXT_DATA as FOLDER_RAW_DATA\n", - "from config import FIGUREFOLDER\n", - "\n", - "\n", - "from vaep.logging import setup_nb_logger\n", - "logger = setup_nb_logger()\n", - "\n", - "\n", - "print(f\"Search Raw-Files on path: {FOLDER_RAW_DATA}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "folders = search_subfolders(path=FOLDER_RAW_DATA, depth=1, exclude_root=True)\n", - "w_folder = widgets.Dropdown(options=folders, description='Select a folder')\n", - "w_folder" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output = MaxQuantOutput(folder=w_folder.value)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Some important columns\n", - "\n", - "Grouped by a namedtuple allowing attribute access" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_col" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## `peptides.txt`\n", - "\n", - "> For reference on final \"result\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pd.options.display.max_columns = len(mq_output.peptides.columns)\n", - "mq_output.peptides" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`peptides.txt` contains aggregated peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "intensities = mq_output.peptides.Intensity\n", - "intensities" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Not all peptides are associated with a Protein or Gene by MQ, although\n", - "there is evidence for the peptide. This is due to potential\n", - "`CON_`taminants in the medium which is encouded by default by MQ." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.peptides[FASTA_KEYS].isna().sum()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## `evidence.txt`\n", - "\n", - "contains\n", - "- retention time for peptides\n", - "- has repeated measures of the same sequences, which are all aggregated in `peptides.txt`\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pd.options.display.max_columns = len(mq_output.evidence.columns)\n", - "mq_output.evidence" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.evidence.Charge.value_counts().sort_index()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = mq_output.evidence[mq_col.RETENTION_TIME] != mq_output.evidence[mq_col.CALIBRATED_RETENTION_TIME]\n", - "print(\"Number of non-matching retention times between calibrated and non-calibrated column:\", mask.sum())\n", - "\n", - "# try:\n", - "# assert mask.sum() == 0, \"More than one replica?\"\n", - "# except AssertionError as e:\n", - "# logger.warning(e)\n", - "assert mask.sum() == 0, \"More than one replica?\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Using only one quality control sample, leaves the initial retention time as is." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "rt = mq_output.evidence[mq_col.CALIBRATED_RETENTION_TIME]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pep_measured_freq_in_evidence = rt.index.value_counts()\n", - "pep_measured_freq_in_evidence.iloc[:10] # top10 repeatedly measured peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "max_observed_pep_evidence = pep_measured_freq_in_evidence.index[0]\n", - "mq_output.evidence.loc[\n", - " max_observed_pep_evidence,\n", - " :\n", - "]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The retention time index is non-unique." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print('The retention time index is unique: {}'.format(rt.index.is_unique))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Peptides observed more than once at different times." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask_duplicated = rt.index.duplicated(keep=False)\n", - "rt_duplicates = rt.loc[mask_duplicated]\n", - "rt_duplicates" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.evidence.loc[mask_duplicated, [\n", - " 'Charge', 'Calibrated retention time', 'Intensity']]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Calculate median intensity and calculate standard deviation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_agg_functions = ['median', 'std']\n", - "\n", - "rt_summary = rt.groupby(level=0).agg(_agg_functions)\n", - "rt_summary" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's see several quartiles for both median and standard deviation (the\n", - "columns are independent from each other) for the retention time" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "rt_summary.describe(percentiles=[0.8, 0.9, 0.95, 0.96, 0.97, 0.98, 0.99])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "rt_summary['median']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A large standard-deviation indicates that the intensity values originate from time points (in min) widely spread." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Peptides observed several times a different points of experimental run" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = rt_summary['std'] > 30.0\n", - "mask_indices = mask[mask].index\n", - "rt.loc[mask_indices]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Peptides with differen RT have different charges." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.evidence.loc[mask_indices]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Model evaluation possibility: Discard samples with several measurements\n", - "from an experiment and predict value. See which intensity measurement\n", - "corresponds more closely." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_peptide = random.choice(mask_indices)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "f'evidence_{_peptide}_{w_folder.value.stem}'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "peptide_view = mq_output.evidence.loc[_peptide]\n", - "peptide_view = (peptide_view[\n", - " vaep.pandas.get_unique_non_unique_columns(peptide_view).non_unique]\n", - " .dropna(axis=1, how='all')\n", - " .set_index('Charge', append=True))\n", - "peptide_view" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fname = w_folder.value.parent / f'evidence_{_peptide}_{w_folder.value.stem}.xlsx'\n", - "peptide_view.to_excel(fname)\n", - "fname" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`Type` column indicates if peptide is based on one or more MS-MS spectra." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.peptides.loc[_peptide].to_frame().T" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Differences in intensities b/w peptides.txt and evidence.txt\n", - "\n", - "\n", - "The intensity reported in `peptides.txt` corresponds to roughly to the\n", - "sum of the intensities found in different scans:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "col_intensity = mq_col.INTENSITY\n", - "try:\n", - "\n", - " assert_almost_equal(\n", - " _pep_int_evidence := mq_output.evidence.loc[_peptide, col_intensity].sum(),\n", - " _pep_int_peptides := mq_output.peptides.loc[_peptide, col_intensity],\n", - " err_msg='Mismatch between evidence.txt summed peptide intensities to reported peptide intensities in peptides.txt')\n", - "except AssertionError as e:\n", - " logging.error(\n", - " f\"{e}\\n Difference: {_pep_int_evidence - _pep_int_peptides:,.2f}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.evidence.loc[_peptide, col_intensity]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.peptides.loc[_peptide, col_intensity]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Make this comparison for all peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_pep_int_evidence = mq_output.evidence.groupby(\n", - " level=0).agg({col_intensity: [sum, len]})\n", - "_pep_int_evidence.columns = [col_intensity, 'count']\n", - "_pep_int_evidence" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_diff = _pep_int_evidence[col_intensity] - \\\n", - " mq_output.peptides[col_intensity].astype(float)\n", - "mask_diff = _diff != 0.0\n", - "_pep_int_evidence.loc[mask_diff].describe()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_diff.loc[mask_diff]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_diff[mask_diff].describe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Several smaller and larger differences in an intensity range way below the detection limit arise for some sequences." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Ideas on source of difference\n", - " - Are all peptides (sequences) which are based on single observations in `evidence.txt` represented as is in `peptides.txt`?\n", - " - how many peptides with more than one PTM have non-zero differences between the sum of intensity values in `evidence.txt` and the respective value in `peptides.txt`?\n", - " - maybe some peptides are filtered based on assignment as contaminent (`CON__`)?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# ToDo see above" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_diff_indices = _diff[mask_diff].index\n", - "# some pep-seq in peptides.txt not in evidence.txt\n", - "_diff_indices = _diff_indices.intersection(mq_output.evidence.index.unique())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sample_index = random.choice(_diff_indices)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.evidence.loc[sample_index]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.peptides.loc[sample_index].to_frame().T" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Modifications" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.evidence.Modifications.value_counts()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Potential contaminant peptides" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `CON__` entries are possible contaminations resulting from sample preparation using a e.g. a serum:\n", - "\n", - "```python\n", - "data_fasta['ENSEMBL:ENSBTAP00000024146']\n", - "data_fasta['P12763'] # bovine serum protein -> present in cell cultures and in list of default contaminant in MQ\n", - "data_fasta['P00735'] # also bovin serum protein\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = mq_output.peptides['Potential contaminant'].notna()\n", - "mq_output.peptides.loc[mask]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Aggregate identifiers in evidence.txt\n", - "\n", - "- `Proteins`: All proteins that contain peptide sequence" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fasta_keys = [\"Proteins\", \"Leading proteins\",\n", - " \"Leading razor protein\", \"Gene names\"]\n", - "mq_output.evidence[fasta_keys]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The protein assignment information is not entirely unique for each group of peptides." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## align intensities and retention time (RT) for peptides\n", - "\n", - "- intensities are values reported in `peptides.txt`\n", - "- some (few) peptides in `peptides.txt` are not in `evidence.txt`, but then probably zero" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "intensities.index" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "seq_w_summed_intensities = intensities.to_frame().merge(\n", - " rt_summary, left_index=True, right_index=True, how='left')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "seq_w_summed_intensities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = ~mq_output.evidence.reset_index(\n", - ")[[\"Sequence\", \"Proteins\", \"Gene names\"]].duplicated()\n", - "mask.index = mq_output.evidence.index" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "diff_ = seq_w_summed_intensities.index.unique().difference(mask.index.unique())\n", - "diff_.to_list()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# mq_output.msms.set_index('Sequence').loc['GIPNMLLSEEETES']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# There is no evidence, but then it is reported in peptides?!\n", - "# Is this the case for more than one MQ-RUN (last or first not written to file?)\n", - "try:\n", - " if len(diff_) > 0:\n", - " mq_output.evidence.loc[diff_]\n", - "except KeyError as e:\n", - " logging.error(e)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.peptides.loc[diff_]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Option: Peptide scan with highest score for repeatedly measured peptides\n", - "\n", - "- only select one of repeated peptide scans, namely the one with the highest score\n", - "- discards information, no summation of peptide intensities\n", - "- yields unique retention time per peptide, by discarding additional information" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "COL_SCORE = 'Score'\n", - "mq_output.evidence.groupby(level=0)[COL_SCORE].max()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask_max_per_seq = mq_output.evidence.groupby(\n", - " level=0)[COL_SCORE].transform(\"max\").eq(mq_output.evidence[COL_SCORE])\n", - "mask_intensity_not_na = mq_output.evidence.Intensity.notna()\n", - "mask = mask_max_per_seq & mask_intensity_not_na" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This leads to a non-unique mapping, as some scores are exactly the same for two peptides." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask_duplicates = mq_output.evidence.loc[mask].sort_values(\n", - " mq_col.INTENSITY).index.duplicated()\n", - "sequences_duplicated = mq_output.evidence.loc[mask].index[mask_duplicates]\n", - "mq_output.evidence.loc[mask].loc[sequences_duplicated, [\n", - " COL_SCORE, mq_col.INTENSITY, mq_col.RETENTION_TIME]] # .groupby(level=0).agg({mq_col.INTENSITY : max})" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = mq_output.evidence.reset_index().sort_values(\n", - " by=[\"Sequence\", \"Score\", mq_col.INTENSITY]).duplicated(subset=[\"Sequence\", \"Score\"], keep='last')\n", - "_sequences = mq_output.evidence.index[mask]\n", - "mq_output.evidence.loc[_sequences, [\n", - " \"Score\", \"Retention time\", mq_col.INTENSITY, \"Proteins\"]]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- random, non missing intensity?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "aggregators = [\"Sequence\", \"Score\", mq_col.INTENSITY]\n", - "mask_intensity_not_na = mq_output.evidence.Intensity.notna()\n", - "seq_max_score_max_intensity = mq_output.evidence.loc[mask_intensity_not_na].reset_index(\n", - ")[aggregators + [\"Proteins\", \"Gene names\"]].sort_values(by=aggregators).set_index(\"Sequence\").groupby(level=0).last()\n", - "seq_max_score_max_intensity" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# drop NA intensities first.\n", - "assert seq_max_score_max_intensity.Intensity.isna().sum() == 0" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Certain peptides have no Protein or gene assigned." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "seq_max_score_max_intensity.isna().sum()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask_seq_selected_not_assigned = seq_max_score_max_intensity.Proteins.isna(\n", - ") | seq_max_score_max_intensity[\"Gene names\"].isna()\n", - "seq_max_score_max_intensity.loc[mask_seq_selected_not_assigned]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "These might be a candiate for evaluating predictions, as the information is measured, but unknown.\n", - "If they cannot be assigned, the closest fit on different genes with\n", - "model predictions could be a criterion for selection" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Create dumps of intensities in `peptides.txt`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# mq_output.evidence.loc[\"AAAGGGGGGAAAAGR\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# ToDo: dump this?\n", - "mq_output.dump_intensity(folder='data/peptides_txt_intensities/')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Create dumps per gene" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Some hundred peptides map to more than two genes" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "seq_max_score_max_intensity[mq_col.GENE_NAMES].str.split(\";\"\n", - " ).apply(lambda x: length(x)\n", - " ).value_counts(\n", - ").sort_index()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Mostly unique genes associated with a peptide." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Select sensible training data per gene\n", - "- sequence coverage information?\n", - "- minimal number or minimal sequence coverage, otherwise discared\n", - "- multiple genes:\n", - " - select first and add reference in others\n", - " - split and dump repeatedly\n", - "\n", - "Load fasta-file information" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "with open(config.FN_FASTA_DB) as f:\n", - " data_fasta = json.load(f)\n", - "print(f'Number of proteins in fasta file DB: {len(data_fasta)}')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# schema validation? Load class with schema?\n", - "# -> Fasta-File creation should save schema with it" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Fasta Entries considered as contaminants by MQ" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask_potential_contaminant = mq_output.peptides['Potential contaminant'] == '+'\n", - "contaminants = mq_output.peptides.loc[mask_potential_contaminant, [mq_col.PROTEINS, mq_col.LEADING_RAZOR_PROTEIN]]\n", - "contaminants.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "unique_cont = contaminants[mq_col.PROTEINS].str.split(';').to_list()\n", - "set_all = set().union(*unique_cont)\n", - "set_cont = {x.split('CON__')[-1] for x in set_all if 'CON__' in x}\n", - "set_proteins_to_remove = set_all.intersection(set_cont)\n", - "set_proteins_to_remove" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "List of proteins which are both in the fasta file and potential contaminants" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = mq_output.peptides[mq_col.LEADING_RAZOR_PROTEIN].isin(set_proteins_to_remove)\n", - "# ToDo: Remove potential contaminants, check evidence.txt\n", - "mq_output.peptides.loc[mask, 'Potential contaminant'].value_counts()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### `id_map`: Find genes based on fasta file\n", - "\n", - "Using `ID_MAP`, all protein entries for that gene are queried and combined." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# # slow! discarded for now\n", - "\n", - "# from config import FN_ID_MAP\n", - "\n", - "# with open(FN_ID_MAP) as f:\n", - "# id_map = json.load(f)\n", - "# id_map = pd.read_json(FN_ID_MAP, orient=\"split\")\n", - "\n", - "# protein_groups_per_gene = id_map.groupby(by=\"gene\")\n", - "# gene_found = []\n", - "# for name, gene_data in protein_groups_per_gene:\n", - "\n", - "# _peptides = set()\n", - "# for protein_id in gene_data.index:\n", - "# _peptides = _peptides.union(p for p_list in data_fasta[protein_id]['peptides']\n", - "# for p in p_list)\n", - "\n", - "# # select intersection of theoretical peptides for gene with observed peptides\n", - "# _matched = mq_output.peptides.index.intersection(_peptides)\n", - "# # add completness?\n", - "# if not _matched.empty and len(_matched) > 3:\n", - "# gene_found.append(name)\n", - "# #\n", - "# if not len(gene_found) % 500 :\n", - "# print(f\"Found {len(gene_found):6}\")\n", - "# print(f\"Total: {len(gene_found):5}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Compare this with the entries in the `Gene names` column of `peptides.txt`\n", - "\n", - "> Mapping is non-unique. MQ has no treshold on number of identified peptides. (How many (unique) peptides does MQ need?)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### `peptides.txt`: Multiple Genes per peptides\n", - "\n", - "- can gene name be collapsed meaningfully?\n", - "- some gene groups share common stem -> can this be used?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.peptides[mq_col.GENE_NAMES].head(10)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "gene_sets_unique = mq_output.peptides[\"Gene names\"].unique()\n", - "\n", - "N_GENE_SETS = len(gene_sets_unique)\n", - "print(f'There are {N_GENE_SETS} unique sets of genes.')\n", - "assert N_GENE_SETS != 0, 'No genes?'\n", - "\n", - "genes_single_unique = mq.get_set_of_genes(gene_sets_unique)\n", - "N_GENE_SINGLE_UNIQUE = len(genes_single_unique)\n", - "\n", - "mq.validate_gene_set(N_GENE_SINGLE_UNIQUE, N_GENE_SETS)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "How often do genes names appear in unique sets?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "genes_counted_each_in_unique_sets = pd.Series(mq.count_genes_in_sets(\n", - " gene_sets=gene_sets_unique))\n", - "\n", - "title_ = 'Frequency of counts for each gene in unique set of genes'\n", - "\n", - "ax = genes_counted_each_in_unique_sets.value_counts().sort_index().plot(\n", - " kind='bar',\n", - " title=title_,\n", - " xlabel='Count of a gene',\n", - " ylabel='Frequency of counts',\n", - " ax=None,\n", - ")\n", - "fig = ax.get_figure()\n", - "\n", - "fig_folder = FIGUREFOLDER / mq_output.folder.stem\n", - "fig_folder.mkdir(exist_ok=True)\n", - "fig.savefig(fig_folder / f'{title_}.pdf')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Unique gene sets with more than one gene:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "gene_sets_unique = pd.Series(gene_sets_unique).dropna()\n", - "\n", - "mask_more_than_one_gene = gene_sets_unique.str.contains(';')\n", - "gene_sets_unique.loc[mask_more_than_one_gene]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Long format for genes - `peptides_with_single_gene`\n", - "\n", - "Expand the rows for sets of genes using [`pandas.DataFrame.explode`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html).\n", - "\n", - "Does a group of peptide only assigns unique set of genes? Genes can have more than one protein.\n", - " - first build groups\n", - " - then see matches (see further below)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptides_with_single_gene = mq.get_peptides_with_single_gene(\n", - " peptides=mq_output.peptides)\n", - "peptides_with_single_gene" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptides_with_single_gene.dtypes" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\n", - " f\"DataFrame has due to unfolding now {len(peptides_with_single_gene)} instead of {len(mq_output.peptides)} rows\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Should peptides from potential contaminants be considered?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = peptides_with_single_gene['Proteins'].str.contains('CON__')\n", - "peptides_with_single_gene.loc[mask]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_mask_con = peptides_with_single_gene.loc[mask, mq_col.PROTEINS].str.split(\";\").apply(\n", - " lambda x: [True if \"CON_\" in item else False for item in x]).apply(all)\n", - "\n", - "assert _mask_con.sum() == 0, \"There are peptides resulting only from possible confounders: {}\".format(\n", - " \", \".join(str(x) for x in peptides_with_single_gene.loc[mask, mq_col.PROTEINS].loc[_mask_con].index))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptides_per_gene = peptides_with_single_gene.value_counts(mq_col.GENE_NAMES)\n", - "peptides_per_gene" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "#### Find genes based on `Gene names` column in elonged data-set\n", - "\n", - "More efficient as it does not query unnecessary data or data twice." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "protein_groups_per_gene = peptides_with_single_gene.groupby(\n", - " by=mq_col.GENE_NAMES, dropna=True)\n", - "\n", - "gene_data = protein_groups_per_gene.get_group(peptides_per_gene.index[3])\n", - "gene_data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "list_of_proteins = gene_data[mq_col.PROTEINS].str.split(';').to_list()\n", - "set_of_proteins = set().union(*list_of_proteins)\n", - "set_of_proteins = {x for x in set_of_proteins if 'CON__' not in x}\n", - "set_of_proteins" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "gene_data[mq_col.PROTEINS].value_counts() # combine? select first in case of a CON_ as leading razor protein?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "protein_id = set_of_proteins.pop()\n", - "print(protein_id)\n", - "data_fasta[protein_id]['seq']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_fasta[protein_id]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Sample completeness\n", - "Find a sample with a certain completeness level:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peps_exact_cleaved = mq.find_exact_cleaved_peptides_for_razor_protein(\n", - " gene_data, fasta_db=data_fasta)\n", - "peps_exact_cleaved[:10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Then search the list of possible peptides originating from the fasta files assuming no miscleavages to the set of found peptides.\n", - "\n", - "- How many unique exact-cleaved peptides can be mapped to any peptide found in the sample (**completness**)?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peps_in_data = gene_data.index\n", - "\n", - "mq.calculate_completness_for_sample(\n", - " peps_exact_cleaved=peps_exact_cleaved,\n", - " peps_in_data=peps_in_data)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The number of peptides found can be then used to calculate the completeness" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Select candidates by completeness of training data in single samples and save by experiment name" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mq_output.folder.stem # needs to go to root?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### GeneData accessor?\n", - "\n", - "- [Registering custom accessors tutorial](https://pandas.pydata.org/pandas-docs/stable/development/extending.html#registering-custom-accessors)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# @pd.api.extensions.register_dataframe_accessor('gene')\n", - "# class GeneDataAccessor:\n", - "\n", - "# COL_INTENSITY = mq_col.INTENSITY\n", - "# COL_RAZOR_PROT = 'Leading razor protein'\n", - "# COL_PROTEINS = 'Proteins'\n", - "# COL_GENE_NAME = 'Gene names'\n", - "\n", - "# COLS_EXPECTED = {COL_INTENSITY, COL_RAZOR_PROT, COL_PROTEINS, COL_GENE_NAME}\n", - "\n", - "# def __init__(self, pandas_df):\n", - "# self._validate(df=pandas_df)\n", - "\n", - "# @classmethod\n", - "# def _validate(cls, df):\n", - "# \"\"\"Verify if expected columns and layout apply to panda.DataFrame (view)\"\"\"\n", - "# _found_columns = cls.COLS_EXPECTED.intersection(df.columns)\n", - "# if not _found_columns == cls.COLS_EXPECTED:\n", - "# raise AttributeError(\"Expected columns not in DataFrame: {}\".format(\n", - "# list(cls.COLS_EXPECTED - _found_columns)))\n", - "# if not len(df[COL_RAZOR_PROT].unique()) != 1:\n", - "\n", - "\n", - "# # GeneDataAccessor(gene_data.drop(mq_col.INTENSITY, axis=1))\n", - "# # GeneDataAccessor(gene_data)\n", - "# # gene_data.drop(mq_col.INTENSITY, axis=1).gene\n", - "# gene_data.gene" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Gene Data Mapper?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class GeneDataMapper:\n", - "\n", - " COL_INTENSITY = mq_col.INTENSITY\n", - " COL_RAZOR_PROT = mq_col.LEADING_RAZOR_PROTEIN\n", - " COL_PROTEINS = mq_col.PROTEINS\n", - " COL_GENE_NAME = mq_col.GENE_NAMES\n", - "\n", - " COLS_EXPECTED = {COL_INTENSITY, COL_RAZOR_PROT,\n", - " COL_PROTEINS, COL_GENE_NAME}\n", - "\n", - " def __init__(self, pandas_df, fasta_dict):\n", - " self._validate(df=pandas_df)\n", - " self._df = pandas_df\n", - " self._fasta_dict = fasta_dict\n", - "\n", - " # self.log?\n", - "\n", - " @classmethod\n", - " def _validate(cls, df):\n", - " \"\"\"Verify if expected columns and layout apply to panda.DataFrame (view)\"\"\"\n", - " _found_columns = cls.COLS_EXPECTED.intersection(df.columns)\n", - " if not _found_columns == cls.COLS_EXPECTED:\n", - " raise AttributeError(\"Expected columns not in DataFrame: {}\".format(\n", - " list(cls.COLS_EXPECTED - _found_columns)))\n", - " if len(df[cls.COL_RAZOR_PROT].unique()) != 1:\n", - " raise ValueError(\n", - " \"Non-unique razor-protein in DataFrame: \", df[cls.COL_RAZOR_PROT].unique())\n", - "\n", - " def __repr__(self):\n", - " return f\"{self.__class__.__name__} at {id(self)}\"\n", - "\n", - "\n", - "GeneDataMapper(gene_data, data_fasta)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Dump samples as json\n", - "\n", - "- select unique gene-names in set (have to be shared by all peptides)\n", - "- dump peptide intensities as json from `peptides.txt`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptides_with_single_gene # long-format with repeated peptide information by gene" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "root_logger = logging.getLogger()\n", - "root_logger.handlers = []\n", - "root_logger.handlers" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "genes_counted_each_in_unique_sets = pd.Series(mq.count_genes_in_sets(\n", - " gene_sets=gene_sets_unique))\n", - "\n", - "# # ToDo: Develop\n", - "# class MaxQuantTrainingDataExtractor():\n", - "# \"\"\"Class to extract training data from `MaxQuantOutput`.\"\"\"\n", - "\n", - "# def __init__(self, out_folder):\n", - "# self.out_folder = Path(out_folder)\n", - "# self.out_folder.mkdir(exist_ok=True)\n", - "# self.fname_template = '{gene}.json'\n", - "\n", - "completeness_per_gene = mq.ExtractFromPeptidesTxt(\n", - " out_folder='train', mq_output_object=mq_output, fasta_db=data_fasta)()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# same code fails in `vaep.io.mq`, ABC needed?\n", - "isinstance(mq_output, MaxQuantOutput), type(mq_output)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Descriptics" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "s_completeness = pd.Series(completeness_per_gene, name='completenes_by_gene')\n", - "s_completeness.describe()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "N_BINS = 20\n", - "ax = s_completeness.plot(\n", - " kind='hist',\n", - " bins=N_BINS,\n", - " xticks=[\n", - " x /\n", - " 100 for x in range(\n", - " 0,\n", - " 101,\n", - " 5)],\n", - " figsize=(\n", - " 10,\n", - " 5),\n", - " rot=90,\n", - " title=f\"Frequency of proportion of observed exact peptides (completness) per razor protein from 0 to 1 in {N_BINS} bins\"\n", - " f\"\\nin sample {mq_output.folder.stem}\")\n", - "\n", - "_ = ax.set_xlabel(\n", - " \"Proportion of exactly observed peptides (including up to 2 mis-cleavages)\")\n", - "\n", - "fig = ax.get_figure()\n", - "fig.tight_layout()\n", - "fig.savefig(FIGUREFOLDER / mq_output.folder.stem / 'freq_completeness.png')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "based on completeness, select valid training data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# continously decrease this number in the scope of the project\n", - "mask = s_completeness > .6\n", - "s_completeness.loc[mask]" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.8.13 ('vaep')", - "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.8.13" - }, - "toc-autonumbering": false, - "vscode": { - "interpreter": { - "hash": "cf83e9cb890c7f96eb0ae04f39a82254555f56a1a0ed2f03b23a8b40fe6cd31c" - } - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/erda_12_explore_raw_MQ_data.py b/project/erda_12_explore_raw_MQ_data.py deleted file mode 100644 index 13b0c6d0d..000000000 --- a/project/erda_12_explore_raw_MQ_data.py +++ /dev/null @@ -1,840 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: Python 3.8.13 ('vaep') -# language: python -# name: python3 -# --- - -# %% [markdown] -# # Explore MaxQuant (MQ) output files of single runs -# -# The `erda_03_training_data.ipynb` notebook does extract information to be used as training data. -# File specific one could also use the retention time analysis to identify _valid_ co-occurring peptides to be use during training. -# Potentially this preprocessing step can be used at inference time. -# -# This notebook contains some relevant analysis for a specific `txt` output-folder in the current project -# -# ##### Analysis overview -# -# > Report for example data -# -# - relation between `peptides.txt` and `evidence.txt` - -# %% -import json -import logging -import random - -import ipywidgets as widgets - -from numpy.testing import assert_almost_equal -from numpy import random -import pandas as pd -# pd.options.display.float_format = '{:,.1f}'.format - -import vaep.pandas -from vaep.pandas import length -from vaep.io.mq import FASTA_KEYS, MaxQuantOutput -from vaep.io import search_subfolders -import vaep.io.mq as mq -from vaep.io.mq import mq_col - -##### CONFIG ##### -import config -from config import FOLDER_MQ_TXT_DATA as FOLDER_RAW_DATA -from config import FIGUREFOLDER - - -from vaep.logging import setup_nb_logger -logger = setup_nb_logger() - - -print(f"Search Raw-Files on path: {FOLDER_RAW_DATA}") - -# %% -folders = search_subfolders(path=FOLDER_RAW_DATA, depth=1, exclude_root=True) -w_folder = widgets.Dropdown(options=folders, description='Select a folder') -w_folder - -# %% -mq_output = MaxQuantOutput(folder=w_folder.value) - -# %% [markdown] -# ## Some important columns -# -# Grouped by a namedtuple allowing attribute access - -# %% -mq_col - -# %% [markdown] -# ## `peptides.txt` -# -# > For reference on final "result" - -# %% -pd.options.display.max_columns = len(mq_output.peptides.columns) -mq_output.peptides - -# %% [markdown] -# `peptides.txt` contains aggregated peptides - -# %% -intensities = mq_output.peptides.Intensity -intensities - -# %% [markdown] -# Not all peptides are associated with a Protein or Gene by MQ, although -# there is evidence for the peptide. This is due to potential -# `CON_`taminants in the medium which is encouded by default by MQ. - -# %% -mq_output.peptides[FASTA_KEYS].isna().sum() - -# %% [markdown] -# ## `evidence.txt` -# -# contains -# - retention time for peptides -# - has repeated measures of the same sequences, which are all aggregated in `peptides.txt` -# - -# %% -pd.options.display.max_columns = len(mq_output.evidence.columns) -mq_output.evidence - -# %% -mq_output.evidence.Charge.value_counts().sort_index() - -# %% -mask = mq_output.evidence[mq_col.RETENTION_TIME] != mq_output.evidence[mq_col.CALIBRATED_RETENTION_TIME] -print("Number of non-matching retention times between calibrated and non-calibrated column:", mask.sum()) - -# try: -# assert mask.sum() == 0, "More than one replica?" -# except AssertionError as e: -# logger.warning(e) -assert mask.sum() == 0, "More than one replica?" - -# %% [markdown] -# Using only one quality control sample, leaves the initial retention time as is. - -# %% -rt = mq_output.evidence[mq_col.CALIBRATED_RETENTION_TIME] - -# %% -pep_measured_freq_in_evidence = rt.index.value_counts() -pep_measured_freq_in_evidence.iloc[:10] # top10 repeatedly measured peptides - -# %% -max_observed_pep_evidence = pep_measured_freq_in_evidence.index[0] -mq_output.evidence.loc[ - max_observed_pep_evidence, - : -] - -# %% [markdown] -# The retention time index is non-unique. - -# %% -print('The retention time index is unique: {}'.format(rt.index.is_unique)) - -# %% [markdown] -# Peptides observed more than once at different times. - -# %% -mask_duplicated = rt.index.duplicated(keep=False) -rt_duplicates = rt.loc[mask_duplicated] -rt_duplicates - -# %% -mq_output.evidence.loc[mask_duplicated, [ - 'Charge', 'Calibrated retention time', 'Intensity']] - -# %% [markdown] -# Calculate median intensity and calculate standard deviation - -# %% -_agg_functions = ['median', 'std'] - -rt_summary = rt.groupby(level=0).agg(_agg_functions) -rt_summary - -# %% [markdown] -# Let's see several quartiles for both median and standard deviation (the -# columns are independent from each other) for the retention time - -# %% -rt_summary.describe(percentiles=[0.8, 0.9, 0.95, 0.96, 0.97, 0.98, 0.99]) - -# %% -rt_summary['median'] - -# %% [markdown] -# A large standard-deviation indicates that the intensity values originate from time points (in min) widely spread. - -# %% [markdown] -# ### Peptides observed several times a different points of experimental run - -# %% -mask = rt_summary['std'] > 30.0 -mask_indices = mask[mask].index -rt.loc[mask_indices] - -# %% [markdown] -# Peptides with differen RT have different charges. - -# %% -mq_output.evidence.loc[mask_indices] - -# %% [markdown] -# Model evaluation possibility: Discard samples with several measurements -# from an experiment and predict value. See which intensity measurement -# corresponds more closely. - -# %% -_peptide = random.choice(mask_indices) - -# %% -f'evidence_{_peptide}_{w_folder.value.stem}' - -# %% - -peptide_view = mq_output.evidence.loc[_peptide] -peptide_view = (peptide_view[ - vaep.pandas.get_unique_non_unique_columns(peptide_view).non_unique] - .dropna(axis=1, how='all') - .set_index('Charge', append=True)) -peptide_view - -# %% -fname = w_folder.value.parent / f'evidence_{_peptide}_{w_folder.value.stem}.xlsx' -peptide_view.to_excel(fname) -fname - -# %% [markdown] -# `Type` column indicates if peptide is based on one or more MS-MS spectra. - -# %% -mq_output.peptides.loc[_peptide].to_frame().T - -# %% [markdown] -# ## Differences in intensities b/w peptides.txt and evidence.txt -# -# -# The intensity reported in `peptides.txt` corresponds to roughly to the -# sum of the intensities found in different scans: - -# %% -col_intensity = mq_col.INTENSITY -try: - - assert_almost_equal( - _pep_int_evidence := mq_output.evidence.loc[_peptide, col_intensity].sum(), - _pep_int_peptides := mq_output.peptides.loc[_peptide, col_intensity], - err_msg='Mismatch between evidence.txt summed peptide intensities to reported peptide intensities in peptides.txt') -except AssertionError as e: - logging.error( - f"{e}\n Difference: {_pep_int_evidence - _pep_int_peptides:,.2f}") - -# %% -mq_output.evidence.loc[_peptide, col_intensity] - -# %% -mq_output.peptides.loc[_peptide, col_intensity] - -# %% [markdown] -# Make this comparison for all peptides - -# %% -_pep_int_evidence = mq_output.evidence.groupby( - level=0).agg({col_intensity: [sum, len]}) -_pep_int_evidence.columns = [col_intensity, 'count'] -_pep_int_evidence - -# %% -_diff = _pep_int_evidence[col_intensity] - \ - mq_output.peptides[col_intensity].astype(float) -mask_diff = _diff != 0.0 -_pep_int_evidence.loc[mask_diff].describe() - -# %% -_diff.loc[mask_diff] - -# %% -_diff[mask_diff].describe() - -# %% [markdown] -# Several smaller and larger differences in an intensity range way below the detection limit arise for some sequences. - -# %% [markdown] -# ### Ideas on source of difference -# - Are all peptides (sequences) which are based on single observations in `evidence.txt` represented as is in `peptides.txt`? -# - how many peptides with more than one PTM have non-zero differences between the sum of intensity values in `evidence.txt` and the respective value in `peptides.txt`? -# - maybe some peptides are filtered based on assignment as contaminent (`CON__`)? - -# %% -# ToDo see above - -# %% -_diff_indices = _diff[mask_diff].index -# some pep-seq in peptides.txt not in evidence.txt -_diff_indices = _diff_indices.intersection(mq_output.evidence.index.unique()) - -# %% -sample_index = random.choice(_diff_indices) - -# %% -mq_output.evidence.loc[sample_index] - -# %% -mq_output.peptides.loc[sample_index].to_frame().T - -# %% [markdown] -# ### Modifications - -# %% -mq_output.evidence.Modifications.value_counts() - -# %% [markdown] -# ### Potential contaminant peptides - -# %% [markdown] -# The `CON__` entries are possible contaminations resulting from sample preparation using a e.g. a serum: -# -# ```python -# data_fasta['ENSEMBL:ENSBTAP00000024146'] -# data_fasta['P12763'] # bovine serum protein -> present in cell cultures and in list of default contaminant in MQ -# data_fasta['P00735'] # also bovin serum protein -# ``` - -# %% -mask = mq_output.peptides['Potential contaminant'].notna() -mq_output.peptides.loc[mask] - -# %% [markdown] -# ### Aggregate identifiers in evidence.txt -# -# - `Proteins`: All proteins that contain peptide sequence - -# %% -fasta_keys = ["Proteins", "Leading proteins", - "Leading razor protein", "Gene names"] -mq_output.evidence[fasta_keys] - -# %% [markdown] -# The protein assignment information is not entirely unique for each group of peptides. - -# %% [markdown] -# ## align intensities and retention time (RT) for peptides -# -# - intensities are values reported in `peptides.txt` -# - some (few) peptides in `peptides.txt` are not in `evidence.txt`, but then probably zero - -# %% -intensities.index - -# %% -seq_w_summed_intensities = intensities.to_frame().merge( - rt_summary, left_index=True, right_index=True, how='left') - -# %% -seq_w_summed_intensities - -# %% -mask = ~mq_output.evidence.reset_index( -)[["Sequence", "Proteins", "Gene names"]].duplicated() -mask.index = mq_output.evidence.index - -# %% -diff_ = seq_w_summed_intensities.index.unique().difference(mask.index.unique()) -diff_.to_list() - -# %% -# mq_output.msms.set_index('Sequence').loc['GIPNMLLSEEETES'] - -# %% -# There is no evidence, but then it is reported in peptides?! -# Is this the case for more than one MQ-RUN (last or first not written to file?) -try: - if len(diff_) > 0: - mq_output.evidence.loc[diff_] -except KeyError as e: - logging.error(e) - -# %% -mq_output.peptides.loc[diff_] - -# %% [markdown] -# ### Option: Peptide scan with highest score for repeatedly measured peptides -# -# - only select one of repeated peptide scans, namely the one with the highest score -# - discards information, no summation of peptide intensities -# - yields unique retention time per peptide, by discarding additional information - -# %% -COL_SCORE = 'Score' -mq_output.evidence.groupby(level=0)[COL_SCORE].max() - -# %% -mask_max_per_seq = mq_output.evidence.groupby( - level=0)[COL_SCORE].transform("max").eq(mq_output.evidence[COL_SCORE]) -mask_intensity_not_na = mq_output.evidence.Intensity.notna() -mask = mask_max_per_seq & mask_intensity_not_na - -# %% [markdown] -# This leads to a non-unique mapping, as some scores are exactly the same for two peptides. - -# %% -mask_duplicates = mq_output.evidence.loc[mask].sort_values( - mq_col.INTENSITY).index.duplicated() -sequences_duplicated = mq_output.evidence.loc[mask].index[mask_duplicates] -mq_output.evidence.loc[mask].loc[sequences_duplicated, [ - COL_SCORE, mq_col.INTENSITY, mq_col.RETENTION_TIME]] # .groupby(level=0).agg({mq_col.INTENSITY : max}) - -# %% -mask = mq_output.evidence.reset_index().sort_values( - by=["Sequence", "Score", mq_col.INTENSITY]).duplicated(subset=["Sequence", "Score"], keep='last') -_sequences = mq_output.evidence.index[mask] -mq_output.evidence.loc[_sequences, [ - "Score", "Retention time", mq_col.INTENSITY, "Proteins"]] - -# %% [markdown] -# - random, non missing intensity? - -# %% -aggregators = ["Sequence", "Score", mq_col.INTENSITY] -mask_intensity_not_na = mq_output.evidence.Intensity.notna() -seq_max_score_max_intensity = mq_output.evidence.loc[mask_intensity_not_na].reset_index( -)[aggregators + ["Proteins", "Gene names"]].sort_values(by=aggregators).set_index("Sequence").groupby(level=0).last() -seq_max_score_max_intensity - -# %% -# drop NA intensities first. -assert seq_max_score_max_intensity.Intensity.isna().sum() == 0 - -# %% [markdown] -# Certain peptides have no Protein or gene assigned. - -# %% -seq_max_score_max_intensity.isna().sum() - -# %% -mask_seq_selected_not_assigned = seq_max_score_max_intensity.Proteins.isna( -) | seq_max_score_max_intensity["Gene names"].isna() -seq_max_score_max_intensity.loc[mask_seq_selected_not_assigned] - -# %% [markdown] -# These might be a candiate for evaluating predictions, as the information is measured, but unknown. -# If they cannot be assigned, the closest fit on different genes with -# model predictions could be a criterion for selection - -# %% [markdown] -# ## Create dumps of intensities in `peptides.txt` - -# %% -# mq_output.evidence.loc["AAAGGGGGGAAAAGR"] - -# %% -# ToDo: dump this? -mq_output.dump_intensity(folder='data/peptides_txt_intensities/') - -# %% [markdown] -# ## Create dumps per gene - -# %% [markdown] -# Some hundred peptides map to more than two genes - -# %% -seq_max_score_max_intensity[mq_col.GENE_NAMES].str.split(";" - ).apply(lambda x: length(x) - ).value_counts( -).sort_index() - -# %% [markdown] -# Mostly unique genes associated with a peptide. - -# %% [markdown] -# ### Select sensible training data per gene -# - sequence coverage information? -# - minimal number or minimal sequence coverage, otherwise discared -# - multiple genes: -# - select first and add reference in others -# - split and dump repeatedly -# -# Load fasta-file information - -# %% -with open(config.FN_FASTA_DB) as f: - data_fasta = json.load(f) -print(f'Number of proteins in fasta file DB: {len(data_fasta)}') - -# %% -# schema validation? Load class with schema? -# -> Fasta-File creation should save schema with it - -# %% [markdown] -# ### Fasta Entries considered as contaminants by MQ - -# %% -mask_potential_contaminant = mq_output.peptides['Potential contaminant'] == '+' -contaminants = mq_output.peptides.loc[mask_potential_contaminant, [mq_col.PROTEINS, mq_col.LEADING_RAZOR_PROTEIN]] -contaminants.head() - -# %% -unique_cont = contaminants[mq_col.PROTEINS].str.split(';').to_list() -set_all = set().union(*unique_cont) -set_cont = {x.split('CON__')[-1] for x in set_all if 'CON__' in x} -set_proteins_to_remove = set_all.intersection(set_cont) -set_proteins_to_remove - -# %% [markdown] -# List of proteins which are both in the fasta file and potential contaminants - -# %% -mask = mq_output.peptides[mq_col.LEADING_RAZOR_PROTEIN].isin(set_proteins_to_remove) -# ToDo: Remove potential contaminants, check evidence.txt -mq_output.peptides.loc[mask, 'Potential contaminant'].value_counts() - -# %% [markdown] -# ### `id_map`: Find genes based on fasta file -# -# Using `ID_MAP`, all protein entries for that gene are queried and combined. - -# %% -# # slow! discarded for now - -# from config import FN_ID_MAP - -# with open(FN_ID_MAP) as f: -# id_map = json.load(f) -# id_map = pd.read_json(FN_ID_MAP, orient="split") - -# protein_groups_per_gene = id_map.groupby(by="gene") -# gene_found = [] -# for name, gene_data in protein_groups_per_gene: - -# _peptides = set() -# for protein_id in gene_data.index: -# _peptides = _peptides.union(p for p_list in data_fasta[protein_id]['peptides'] -# for p in p_list) - -# # select intersection of theoretical peptides for gene with observed peptides -# _matched = mq_output.peptides.index.intersection(_peptides) -# # add completness? -# if not _matched.empty and len(_matched) > 3: -# gene_found.append(name) -# # -# if not len(gene_found) % 500 : -# print(f"Found {len(gene_found):6}") -# print(f"Total: {len(gene_found):5}") - -# %% [markdown] -# Compare this with the entries in the `Gene names` column of `peptides.txt` -# -# > Mapping is non-unique. MQ has no treshold on number of identified peptides. (How many (unique) peptides does MQ need?) - -# %% [markdown] -# ### `peptides.txt`: Multiple Genes per peptides -# -# - can gene name be collapsed meaningfully? -# - some gene groups share common stem -> can this be used? - -# %% -mq_output.peptides[mq_col.GENE_NAMES].head(10) - -# %% -gene_sets_unique = mq_output.peptides["Gene names"].unique() - -N_GENE_SETS = len(gene_sets_unique) -print(f'There are {N_GENE_SETS} unique sets of genes.') -assert N_GENE_SETS != 0, 'No genes?' - -genes_single_unique = mq.get_set_of_genes(gene_sets_unique) -N_GENE_SINGLE_UNIQUE = len(genes_single_unique) - -mq.validate_gene_set(N_GENE_SINGLE_UNIQUE, N_GENE_SETS) - -# %% [markdown] -# How often do genes names appear in unique sets? - -# %% -genes_counted_each_in_unique_sets = pd.Series(mq.count_genes_in_sets( - gene_sets=gene_sets_unique)) - -title_ = 'Frequency of counts for each gene in unique set of genes' - -ax = genes_counted_each_in_unique_sets.value_counts().sort_index().plot( - kind='bar', - title=title_, - xlabel='Count of a gene', - ylabel='Frequency of counts', - ax=None, -) -fig = ax.get_figure() - -fig_folder = FIGUREFOLDER / mq_output.folder.stem -fig_folder.mkdir(exist_ok=True) -fig.savefig(fig_folder / f'{title_}.pdf') - -# %% [markdown] -# Unique gene sets with more than one gene: - -# %% -gene_sets_unique = pd.Series(gene_sets_unique).dropna() - -mask_more_than_one_gene = gene_sets_unique.str.contains(';') -gene_sets_unique.loc[mask_more_than_one_gene] - -# %% [markdown] -# ### Long format for genes - `peptides_with_single_gene` -# -# Expand the rows for sets of genes using [`pandas.DataFrame.explode`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html). -# -# Does a group of peptide only assigns unique set of genes? Genes can have more than one protein. -# - first build groups -# - then see matches (see further below) -# - -# %% -peptides_with_single_gene = mq.get_peptides_with_single_gene( - peptides=mq_output.peptides) -peptides_with_single_gene - -# %% -peptides_with_single_gene.dtypes - -# %% -print( - f"DataFrame has due to unfolding now {len(peptides_with_single_gene)} instead of {len(mq_output.peptides)} rows") - -# %% [markdown] -# Should peptides from potential contaminants be considered? - -# %% -mask = peptides_with_single_gene['Proteins'].str.contains('CON__') -peptides_with_single_gene.loc[mask] - -# %% -_mask_con = peptides_with_single_gene.loc[mask, mq_col.PROTEINS].str.split(";").apply( - lambda x: [True if "CON_" in item else False for item in x]).apply(all) - -assert _mask_con.sum() == 0, "There are peptides resulting only from possible confounders: {}".format( - ", ".join(str(x) for x in peptides_with_single_gene.loc[mask, mq_col.PROTEINS].loc[_mask_con].index)) - -# %% -peptides_per_gene = peptides_with_single_gene.value_counts(mq_col.GENE_NAMES) -peptides_per_gene - -# %% [markdown] -# -# #### Find genes based on `Gene names` column in elonged data-set -# -# More efficient as it does not query unnecessary data or data twice. - -# %% -protein_groups_per_gene = peptides_with_single_gene.groupby( - by=mq_col.GENE_NAMES, dropna=True) - -gene_data = protein_groups_per_gene.get_group(peptides_per_gene.index[3]) -gene_data - -# %% -list_of_proteins = gene_data[mq_col.PROTEINS].str.split(';').to_list() -set_of_proteins = set().union(*list_of_proteins) -set_of_proteins = {x for x in set_of_proteins if 'CON__' not in x} -set_of_proteins - -# %% -gene_data[mq_col.PROTEINS].value_counts() # combine? select first in case of a CON_ as leading razor protein? - -# %% -protein_id = set_of_proteins.pop() -print(protein_id) -data_fasta[protein_id]['seq'] - -# %% -data_fasta[protein_id] - -# %% [markdown] -# ### Sample completeness -# Find a sample with a certain completeness level: - -# %% -peps_exact_cleaved = mq.find_exact_cleaved_peptides_for_razor_protein( - gene_data, fasta_db=data_fasta) -peps_exact_cleaved[:10] - -# %% [markdown] -# Then search the list of possible peptides originating from the fasta files assuming no miscleavages to the set of found peptides. -# -# - How many unique exact-cleaved peptides can be mapped to any peptide found in the sample (**completness**)? - -# %% -peps_in_data = gene_data.index - -mq.calculate_completness_for_sample( - peps_exact_cleaved=peps_exact_cleaved, - peps_in_data=peps_in_data) - -# %% [markdown] -# The number of peptides found can be then used to calculate the completeness - -# %% [markdown] -# Select candidates by completeness of training data in single samples and save by experiment name - -# %% -mq_output.folder.stem # needs to go to root? - -# %% [markdown] -# ### GeneData accessor? -# -# - [Registering custom accessors tutorial](https://pandas.pydata.org/pandas-docs/stable/development/extending.html#registering-custom-accessors) - -# %% -# @pd.api.extensions.register_dataframe_accessor('gene') -# class GeneDataAccessor: - -# COL_INTENSITY = mq_col.INTENSITY -# COL_RAZOR_PROT = 'Leading razor protein' -# COL_PROTEINS = 'Proteins' -# COL_GENE_NAME = 'Gene names' - -# COLS_EXPECTED = {COL_INTENSITY, COL_RAZOR_PROT, COL_PROTEINS, COL_GENE_NAME} - -# def __init__(self, pandas_df): -# self._validate(df=pandas_df) - -# @classmethod -# def _validate(cls, df): -# """Verify if expected columns and layout apply to panda.DataFrame (view)""" -# _found_columns = cls.COLS_EXPECTED.intersection(df.columns) -# if not _found_columns == cls.COLS_EXPECTED: -# raise AttributeError("Expected columns not in DataFrame: {}".format( -# list(cls.COLS_EXPECTED - _found_columns))) -# if not len(df[COL_RAZOR_PROT].unique()) != 1: - - -# # GeneDataAccessor(gene_data.drop(mq_col.INTENSITY, axis=1)) -# # GeneDataAccessor(gene_data) -# # gene_data.drop(mq_col.INTENSITY, axis=1).gene -# gene_data.gene - -# %% [markdown] -# ### Gene Data Mapper? - -# %% -class GeneDataMapper: - - COL_INTENSITY = mq_col.INTENSITY - COL_RAZOR_PROT = mq_col.LEADING_RAZOR_PROTEIN - COL_PROTEINS = mq_col.PROTEINS - COL_GENE_NAME = mq_col.GENE_NAMES - - COLS_EXPECTED = {COL_INTENSITY, COL_RAZOR_PROT, - COL_PROTEINS, COL_GENE_NAME} - - def __init__(self, pandas_df, fasta_dict): - self._validate(df=pandas_df) - self._df = pandas_df - self._fasta_dict = fasta_dict - - # # self.log? - - @classmethod - def _validate(cls, df): - """Verify if expected columns and layout apply to panda.DataFrame (view)""" - _found_columns = cls.COLS_EXPECTED.intersection(df.columns) - if not _found_columns == cls.COLS_EXPECTED: - raise AttributeError("Expected columns not in DataFrame: {}".format( - list(cls.COLS_EXPECTED - _found_columns))) - if len(df[cls.COL_RAZOR_PROT].unique()) != 1: - raise ValueError( - "Non-unique razor-protein in DataFrame: ", df[cls.COL_RAZOR_PROT].unique()) - - def __repr__(self): - return f"{self.__class__.__name__} at {id(self)}" - - -GeneDataMapper(gene_data, data_fasta) - -# %% [markdown] -# ### Dump samples as json -# -# - select unique gene-names in set (have to be shared by all peptides) -# - dump peptide intensities as json from `peptides.txt` - -# %% -peptides_with_single_gene # long-format with repeated peptide information by gene - -# %% -root_logger = logging.getLogger() -root_logger.handlers = [] -root_logger.handlers - -# %% -genes_counted_each_in_unique_sets = pd.Series(mq.count_genes_in_sets( - gene_sets=gene_sets_unique)) - -# # ToDo: Develop -# class MaxQuantTrainingDataExtractor(): -# """Class to extract training data from `MaxQuantOutput`.""" - -# def __init__(self, out_folder): -# self.out_folder = Path(out_folder) -# self.out_folder.mkdir(exist_ok=True) -# self.fname_template = '{gene}.json' - -completeness_per_gene = mq.ExtractFromPeptidesTxt( - out_folder='train', mq_output_object=mq_output, fasta_db=data_fasta)() - -# %% -# same code fails in `vaep.io.mq`, ABC needed? -isinstance(mq_output, MaxQuantOutput), type(mq_output) - -# %% [markdown] -# #### Descriptics - -# %% -s_completeness = pd.Series(completeness_per_gene, name='completenes_by_gene') -s_completeness.describe() - -# %% -N_BINS = 20 -ax = s_completeness.plot( - kind='hist', - bins=N_BINS, - xticks=[ - x / - 100 for x in range( - 0, - 101, - 5)], - figsize=( - 10, - 5), - rot=90, - title=f"Frequency of proportion of observed exact peptides (completness) per razor protein from 0 to 1 in {N_BINS} bins" - f"\nin sample {mq_output.folder.stem}") - -_ = ax.set_xlabel( - "Proportion of exactly observed peptides (including up to 2 mis-cleavages)") - -fig = ax.get_figure() -fig.tight_layout() -fig.savefig(FIGUREFOLDER / mq_output.folder.stem / 'freq_completeness.png') - -# %% [markdown] -# based on completeness, select valid training data - -# %% -# continously decrease this number in the scope of the project -mask = s_completeness > .6 -s_completeness.loc[mask] diff --git a/project/erda_data_available.ipynb b/project/erda_data_available.ipynb deleted file mode 100644 index 8213b7ae1..000000000 --- a/project/erda_data_available.ipynb +++ /dev/null @@ -1,214 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "a1cac16d-ce04-4573-b98b-ac87f1abdf4c", - "metadata": {}, - "outputs": [], - "source": [ - "from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES\n", - "import logging\n", - "import matplotlib\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "import vaep\n", - "from vaep.io import data_objects\n", - "from vaep.logging import setup_nb_logger\n", - "setup_nb_logger(level=logging.INFO)\n", - "\n", - "\n", - "FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES" - ] - }, - { - "cell_type": "markdown", - "id": "1a3645b4", - "metadata": {}, - "source": [ - "## Aggregated Peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "81592213", - "metadata": {}, - "outputs": [], - "source": [ - "peptide_counter = data_objects.PeptideCounter(FNAME_C_PEPTIDES)\n", - "N_SAMPLES = len(peptide_counter.loaded)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c3532c20", - "metadata": {}, - "outputs": [], - "source": [ - "peptide_counter" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cecb0d20", - "metadata": {}, - "outputs": [], - "source": [ - "peptide_counts = peptide_counter.get_df_counts()\n", - "# peptide_counts.index += 1\n", - "peptide_counts.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dec794c3-5b0f-481a-a14f-e84c231c6365", - "metadata": {}, - "outputs": [], - "source": [ - "peptide_counts.describe(percentiles=np.linspace(0.1, 1, 10))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fc5d608f-4969-4964-b03f-923d706a5b33", - "metadata": {}, - "outputs": [], - "source": [ - "vaep.plotting.make_large_descriptors()\n", - "ax = peptide_counter.plot_counts()" - ] - }, - { - "cell_type": "markdown", - "id": "6d75c390", - "metadata": {}, - "source": [ - "## Evidence - Peptides by charge and modifications\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2edab869", - "metadata": {}, - "outputs": [], - "source": [ - "evidence_counter = data_objects.EvidenceCounter(FNAME_C_EVIDENCE)\n", - "evidence_count = evidence_counter.get_df_counts()\n", - "evidence_count.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8a9f11bd", - "metadata": {}, - "outputs": [], - "source": [ - "ax = evidence_counter.plot_counts()" - ] - }, - { - "cell_type": "markdown", - "id": "9a980a8e", - "metadata": {}, - "source": [ - "## Protein Groups" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "85264cf5", - "metadata": {}, - "outputs": [], - "source": [ - "pg_counter = data_objects.ProteinGroupsCounter(FNAME_C_PG)\n", - "pg_count = pg_counter.get_df_counts()\n", - "pg_count.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6d060cd5", - "metadata": {}, - "outputs": [], - "source": [ - "ax = pg_counter.plot_counts()" - ] - }, - { - "cell_type": "markdown", - "id": "cf95d49f", - "metadata": {}, - "source": [ - "## Genes" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "30623792", - "metadata": { - "lines_to_next_cell": 2 - }, - "outputs": [], - "source": [ - "gene_counter = data_objects.GeneCounter(FNAME_C_GENES)\n", - "gene_count = gene_counter.get_df_counts()\n", - "gene_count.head() # remove NaN entry" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "18f788c4", - "metadata": {}, - "outputs": [], - "source": [ - "gene_count = gene_count.iloc[1:]\n", - "gene_count.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "805a3ccc", - "metadata": {}, - "outputs": [], - "source": [ - "ax = gene_counter.plot_counts(df_counts=gene_count) # provide manuelly manipulated gene counts" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/project/erda_data_available.py b/project/erda_data_available.py deleted file mode 100644 index f7decce5c..000000000 --- a/project/erda_data_available.py +++ /dev/null @@ -1,91 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: vaep -# language: python -# name: vaep -# --- - -# %% -from config import FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES -import logging -import matplotlib -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd - -import vaep -from vaep.io import data_objects -from vaep.logging import setup_nb_logger -setup_nb_logger(level=logging.INFO) - - -FNAME_C_PEPTIDES, FNAME_C_EVIDENCE, FNAME_C_PG, FNAME_C_GENES - -# %% [markdown] -# ## Aggregated Peptides - -# %% -peptide_counter = data_objects.PeptideCounter(FNAME_C_PEPTIDES) -N_SAMPLES = len(peptide_counter.loaded) - -# %% -peptide_counter - -# %% -peptide_counts = peptide_counter.get_df_counts() -# peptide_counts.index += 1 -peptide_counts.head() - -# %% -peptide_counts.describe(percentiles=np.linspace(0.1, 1, 10)) - -# %% -vaep.plotting.make_large_descriptors() -ax = peptide_counter.plot_counts() - -# %% [markdown] -# ## Evidence - Peptides by charge and modifications -# -# - -# %% -evidence_counter = data_objects.EvidenceCounter(FNAME_C_EVIDENCE) -evidence_count = evidence_counter.get_df_counts() -evidence_count.head() - -# %% -ax = evidence_counter.plot_counts() - -# %% [markdown] -# ## Protein Groups - -# %% -pg_counter = data_objects.ProteinGroupsCounter(FNAME_C_PG) -pg_count = pg_counter.get_df_counts() -pg_count.head() - -# %% -ax = pg_counter.plot_counts() - -# %% [markdown] -# ## Genes - -# %% -gene_counter = data_objects.GeneCounter(FNAME_C_GENES) -gene_count = gene_counter.get_df_counts() -gene_count.head() # remove NaN entry - - -# %% -gene_count = gene_count.iloc[1:] -gene_count.head() - -# %% -ax = gene_counter.plot_counts(df_counts=gene_count) # provide manuelly manipulated gene counts diff --git a/project/misc_FASTA_data_agg_by_gene.ipynb b/project/misc_FASTA_data_agg_by_gene.ipynb deleted file mode 100644 index fc31a5697..000000000 --- a/project/misc_FASTA_data_agg_by_gene.ipynb +++ /dev/null @@ -1,239 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Protein sequence aggregation by gene" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from collections import defaultdict\n", - "import itertools\n", - "import json\n", - "from pprint import pprint\n", - "from tqdm.notebook import tqdm\n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "from Bio import Align\n", - "\n", - "from config import FN_FASTA_DB\n", - "from config import fasta_entry as fasta_keys" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "with open(FN_FASTA_DB) as f:\n", - " data_fasta = json.load(f) # , indent=4, sort_keys=False)\n", - "len(data_fasta)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "gene_isotopes = defaultdict(list)\n", - "protein_wo_gene = []\n", - "for key, fasta_entry in tqdm(data_fasta.items()):\n", - " gene = fasta_entry[fasta_keys.gene]\n", - " if gene:\n", - " gene_isotopes[gene].append(key)\n", - " else:\n", - " protein_wo_gene.append(key)\n", - "\n", - "print(f\"#{len(protein_wo_gene)} proteins have not gene associated: {', '.join(protein_wo_gene[:10])}, ...\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "gene = 'ACTG1' # Actin as a contaminant protein\n", - "gene_isotopes[gene]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for isotope in gene_isotopes[gene]:\n", - " pprint(data_fasta[isotope])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Sequences" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sequences = {}\n", - "for isotope in gene_isotopes[gene]:\n", - " sequences[isotope] = data_fasta[isotope][fasta_keys.seq]\n", - "sequences" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sorted(sequences.values(), key=len)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sequences = pd.Series(sequences)\n", - "sequences.str.len()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "aligner = Align.PairwiseAligner()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Identical? Maybe check if this is more than once the case?\n", - "alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3I0'])\n", - "for alignment in alignments:\n", - " print(alignment)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_fasta['I3L1U9'][fasta_keys.seq] == data_fasta['I3L3I0'][fasta_keys.seq]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3R2']) # Identical?\n", - "for alignment in alignments:\n", - " print(alignment)\n", - " break" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "alignments = aligner.align(sequences.loc['P63261'], sequences.loc['K7EM38']) # Identical?\n", - "for alignment in alignments:\n", - " print(alignment)\n", - " break" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Unique Peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptides = {}\n", - "for isotope in gene_isotopes[gene]:\n", - " sequences[isotope] = data_fasta[isotope][fasta_keys.peptides][0]\n", - "\n", - "for peptides in itertools.zip_longest(*sequences.values, fillvalue=''):\n", - " if len(set(peptides)) == 1:\n", - " print(f'all identical: {peptides[0]}')\n", - " else:\n", - " print('\\t'.join(peptides))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for j, peptides in enumerate(sequences.values):\n", - " if j == 0:\n", - " set_overlap = set(peptides)\n", - " else:\n", - " set_overlap = set_overlap.intersection(peptides)\n", - "set_overlap" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/misc_FASTA_data_agg_by_gene.py b/project/misc_FASTA_data_agg_by_gene.py deleted file mode 100644 index 072b02b90..000000000 --- a/project/misc_FASTA_data_agg_by_gene.py +++ /dev/null @@ -1,120 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: vaep -# language: python -# name: vaep -# --- - -# %% [markdown] -# # Protein sequence aggregation by gene - -# %% -from collections import defaultdict -import itertools -import json -from pprint import pprint -from tqdm.notebook import tqdm - -import numpy as np -import pandas as pd - -from Bio import Align - -from config import FN_FASTA_DB -from config import fasta_entry as fasta_keys - -# %% -with open(FN_FASTA_DB) as f: - data_fasta = json.load(f) # , indent=4, sort_keys=False) -len(data_fasta) - -# %% -gene_isotopes = defaultdict(list) -protein_wo_gene = [] -for key, fasta_entry in tqdm(data_fasta.items()): - gene = fasta_entry[fasta_keys.gene] - if gene: - gene_isotopes[gene].append(key) - else: - protein_wo_gene.append(key) - -print(f"#{len(protein_wo_gene)} proteins have not gene associated: {', '.join(protein_wo_gene[:10])}, ...") - -# %% -gene = 'ACTG1' # Actin as a contaminant protein -gene_isotopes[gene] - -# %% -for isotope in gene_isotopes[gene]: - pprint(data_fasta[isotope]) - -# %% [markdown] -# ## Sequences - -# %% -sequences = {} -for isotope in gene_isotopes[gene]: - sequences[isotope] = data_fasta[isotope][fasta_keys.seq] -sequences - -# %% -sorted(sequences.values(), key=len) - -# %% -sequences = pd.Series(sequences) -sequences.str.len() - -# %% -aligner = Align.PairwiseAligner() - -# %% -# Identical? Maybe check if this is more than once the case? -alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3I0']) -for alignment in alignments: - print(alignment) - -# %% -data_fasta['I3L1U9'][fasta_keys.seq] == data_fasta['I3L3I0'][fasta_keys.seq] - -# %% -alignments = aligner.align(sequences.loc['I3L1U9'], sequences.loc['I3L3R2']) # Identical? -for alignment in alignments: - print(alignment) - break - -# %% -alignments = aligner.align(sequences.loc['P63261'], sequences.loc['K7EM38']) # Identical? -for alignment in alignments: - print(alignment) - break - -# %% [markdown] -# ## Unique Peptides - -# %% -peptides = {} -for isotope in gene_isotopes[gene]: - sequences[isotope] = data_fasta[isotope][fasta_keys.peptides][0] - -for peptides in itertools.zip_longest(*sequences.values, fillvalue=''): - if len(set(peptides)) == 1: - print(f'all identical: {peptides[0]}') - else: - print('\t'.join(peptides)) - -# %% -for j, peptides in enumerate(sequences.values): - if j == 0: - set_overlap = set(peptides) - else: - set_overlap = set_overlap.intersection(peptides) -set_overlap - -# %% diff --git a/project/misc_FASTA_tryptic_digest.ipynb b/project/misc_FASTA_tryptic_digest.ipynb deleted file mode 100644 index a45249d10..000000000 --- a/project/misc_FASTA_tryptic_digest.ipynb +++ /dev/null @@ -1,1281 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Process FASTA files\n", - "> uses only the provided fasta files in `src.config.py` by `FOLDER_FASTA`\n", - "\n", - "- create theoretically considered peptides considered by search engines\n", - "- dump results as human readable json to `FN_FASTA_DB` file specifed in src.config.\n", - "\n", - "> Based on notebook received by [Annelaura Bach](https://www.cpr.ku.dk/staff/mann-group/?pure=en/persons/443836) and created by Johannes B. Müller \\[[scholar](https://scholar.google.com/citations?user=Rn1OS8oAAAAJ&hl=de), [MPI Biochemistry](https://www.biochem.mpg.de/person/93696/2253)\\]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "from collections import defaultdict, namedtuple\n", - "import os\n", - "import json\n", - "import logging\n", - "from pathlib import Path\n", - "\n", - "# import matplotlib\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pandas as pd\n", - "from tqdm.notebook import tqdm" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from vaep.fasta import cleave_to_tryptic\n", - "from vaep.fasta import iterFlatten\n", - "from vaep.fasta import count_peptide_matches\n", - "from vaep.fasta import read_fasta\n", - "from vaep.io import search_files\n", - "from vaep.pandas import combine_value_counts\n", - "from vaep.databases.uniprot import query_uniprot_id_mapping\n", - "from vaep.utils import sample_iterable\n", - "from vaep.plotting import _savefig" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from config import FN_FASTA_DB\n", - "from config import FIGUREFOLDER\n", - "from config import FN_ID_MAP\n", - "from config import FN_PROT_GENE_MAP\n", - "from config import FN_PEP_TO_PROT\n", - "\n", - "from config import KEY_FASTA_HEADER, KEY_FASTA_SEQ, KEY_GENE_NAME, KEY_PEPTIDES" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Core Functionality - Example\n", - "\n", - "- write tests for core functinality\n", - "- refactor to file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "test_data = {\n", - " \"meta\": \">tr|A0A024R1R8|A0A024R1R8_HUMAN HCG2014768, isoform CRA_a OS=Homo sapiens OX=9606 GN=hCG_2014768 PE=4 SV=1\",\n", - " \"seq\": \"MSSHEGGKKKALKQPKKQAKEMDEEEKAFKQKQKEEQKKLEVLKAKVVGKGPLATGGIKKSGKK\",\n", - " \"peptides\": [\n", - " \"MSSHEGGK\",\n", - " \"EMDEEEK\",\n", - " \"GPLATGGIK\"],\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "regex is slower than native string replacing and splitting in Python" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# import re\n", - "# cut_by_trypsin = re.compile('([^K]+K)|([^R]+R)')\n", - "# _res = cut_by_trypsin.split(test_data['seq'])\n", - "# [_pep for _pep in _res if _pep != '' and _pep != None]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "- map peptide set of peptides (how to deal with mis-cleavages?)\n", - " - mis-cleavages can happen both to the peptide before and after.\n", - " > `pep1, pep2, pep3, pep4, pep5`\n", - " > `pep1pep2, pep2pep3, pep3pep4, pep4pep5`\n", - " - sliding windows can pass trough the list of peptides - should work with recursion" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "l_peptides = test_data[\"seq\"].replace(\"K\", \"K \").replace(\"R\", \"R \").split()\n", - "l_peptides" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`add_rxk` should add pattern of starting R and trailing K ?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "last_pep = \"\"\n", - "temp_peps = []\n", - "num_missed_cleavages = 1\n", - "add_rxk = True\n", - "\n", - "sec_last_pep = \"\"\n", - "\n", - "pep_rdx = []\n", - "\n", - "for pep in l_peptides:\n", - " if last_pep != \"\":\n", - " temp_peps.append(last_pep + pep)\n", - " if add_rxk and sec_last_pep != \"\" and len(sec_last_pep) <= 2:\n", - " _pep_rxk = sec_last_pep + last_pep + pep\n", - " print(_pep_rxk)\n", - " pep_rdx.append(_pep_rxk)\n", - " temp_peps.append(_pep_rxk)\n", - "\n", - " sec_last_pep = last_pep # sec_last_pep, last_pep = last_pep, pep ?\n", - " last_pep = pep\n", - "temp_peps" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "repr(pep_rdx)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Missed cleavages core functionality (adapted)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "example_peptides_fasta = cleave_to_tryptic(\n", - " test_data[\"seq\"], num_missed_cleavages=2, add_rxk=True\n", - ")\n", - "print(\"number of peptides: \", [len(_l) for _l in example_peptides_fasta])\n", - "example_peptides_fasta[-1]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"\".join(example_peptides_fasta[0]), *example_peptides_fasta, sep=\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "rdx peptides are a subset of two missed cleavage sites peptides. There\n", - "are omitted when two and more cleavage site can be skipped." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "example_peptides_fasta = cleave_to_tryptic(\n", - " test_data[\"seq\"], num_missed_cleavages=1, add_rxk=True\n", - ")\n", - "print(\"number of peptides: \", [len(_l) for _l in example_peptides_fasta])\n", - "example_peptides_fasta[-1]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Data Structure is no a list of list. Maybe this could be improved.\n", - "Information what kind of type the peptide is from, is still interesting." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Process Fasta Files\n", - "\n", - "First define input Folder and the file location of the created peptides:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fasta_files = search_files(path=\".\", query=\".fasta\")\n", - "print(fasta_files)\n", - "print(\"\\n\".join(fasta_files.files))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define Setup\n", - "\n", - "Set input FASTA, Output .txt name, lower legth cutoff, missed cleavages and if to report reverse.\n", - "\n", - "Tryptic digest of Fastas to Peptides >6 in list for matching with measured peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "CUTOFF_LEN_PEP = 7\n", - "MAX_MISSED_CLEAVAGES = 2 # default in MaxQuant\n", - "DECOY_REVERSE = False\n", - "SUMMARY_FILE = \"tex/fasta_tryptic_analysis.tex\"\n", - "\n", - "_summary_text = (\n", - " \"The theoretical analysis of the fasta files gives an idea about how many possible peptides \\n\"\n", - " \"can be expected by cleaving proteins using trypsin. The hyperparameters for peptide creation are \\n\"\n", - " f\"to consider the minimal peptide length to be {CUTOFF_LEN_PEP} amino acids, \\n\"\n", - " f\"to consider a maximum of {MAX_MISSED_CLEAVAGES} missed cleavage sites (default in MaxQuant) and \\n\"\n", - " f\"to {'not ' if not DECOY_REVERSE else ''}add decoy peptides by reversing peptide sequences. \\n\"\n", - ")\n", - "print(_summary_text, sep=\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "From the [Fasta Meta information](https://ebi14.uniprot.org/help/fasta-headers) the Identifier is extracted.\n", - "\n", - "```\n", - ">db|UniqueIdentifier|EntryName ProteinName OS=OrganismName OX=OrganismIdentifier [GN=GeneName ]PE=ProteinExistence SV=SequenceVersion\n", - "```\n", - "- db is `sp` for UniProtKB/Swiss-Prot and `tr` for UniProtKB/TrEMBL.\n", - "- `UniqueIdentifier` is the primary *accession number* of the UniProtKB entry. (seems to be used by MQ)\n", - "- `EntryName` is the entry name of the UniProtKB entry.\n", - "- `ProteinName` is the recommended name of the UniProtKB entry as annotated in the *RecName* field. For UniProtKB/TrEMBL entries without a *RecName* field, the *SubName* field is used. In case of multiple SubNames, the first one is used. The 'precursor' attribute is excluded, 'Fragment' is included with the name if applicable." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`>tr` or `>sp`" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Schema for single fasta entry" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "\n", - "data_fasta = {}\n", - "\n", - "# # add Schema?\n", - "# schema_fasta_entry = {\n", - "# KEY_FASTA_HEADER: str,\n", - "# KEY_GENE_NAME: str,\n", - "# KEY_FASTA_SEQ: str,\n", - "# KEY_PEPTIDES: (list, (2,2))\n", - "# }\n", - "# # or dataclass\n", - "# from dataclasses import make_dataclass\n", - "# FastaEntry = make_dataclass(cls_name='FastaEntry',\n", - "# fields=[\n", - "# (KEY_FASTA_HEADER, 'str'),\n", - "# (KEY_GENE_NAME, 'str'),\n", - "# (KEY_FASTA_SEQ, 'str'),\n", - "# (KEY_PEPTIDES, list)\n", - "# ])\n", - "# # or namedtuple\n", - "# FastaEntry = namedtuple('FastaEntry', [KEY_FASTA_HEADER, KEY_GENE_NAME, KEY_FASTA_SEQ, KEY_PEPTIDES])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "How to validate schema of fasta entry stored as dictionary?\n", - "- [schema](https://stackoverflow.com/questions/45812387/how-to-validate-structure-or-schema-of-dictionary-in-python) validation in python discussion" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Process Fasta file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for _fasta in tqdm(fasta_files.files):\n", - "\n", - " with open(_fasta) as fp:\n", - " for i, (metainfo, seq) in tqdm(enumerate(read_fasta(fp))):\n", - " identifier = metainfo.split(\"|\")[1]\n", - " gene = \"|\".join([x.split(\"=\")[-1] for x in metainfo.split() if \"GN=\" in x])\n", - " if identifier in data_fasta:\n", - " raise ValueError(\"Key seen before: {}\".format(identifier))\n", - " _all_peptides = cleave_to_tryptic(\n", - " seq, num_missed_cleavages=MAX_MISSED_CLEAVAGES, reversed=DECOY_REVERSE\n", - " )\n", - " data_fasta[identifier] = {\n", - " KEY_FASTA_HEADER: metainfo,\n", - " KEY_GENE_NAME: gene,\n", - " KEY_FASTA_SEQ: seq,\n", - " KEY_PEPTIDES: [\n", - " [_pep for _pep in _peptides if len(_pep) >= CUTOFF_LEN_PEP]\n", - " for _peptides in _all_peptides\n", - " ],\n", - " }" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`fasta_data` holds all information to pick a subset of peptides from peptides intensity tables" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# from random import sample\n", - "# sample_ids = sample(list(data_fasta), 10)\n", - "# for _id in sample_ids:\n", - "# print(\"Unique Identifier: {}: \\n\\t AA-Seq: {} \\n\\t Header: {} \\n\\t Peptides: {}\\n\".format(_id, data_fasta[_id]['seq'], data_fasta[_id]['meta'], data_fasta[_id]['peptides']))\n", - "data_fasta[\"A0A024R1R8\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "d_seq_length = {}\n", - "for _key, _data in data_fasta.items():\n", - " d_seq_length[_key] = len(_data[KEY_FASTA_SEQ])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "d_seq_length = pd.Series(d_seq_length)\n", - "d_seq_length.describe()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "test_series = pd.Series({\"A\": 4, \"B\": 1, \"C\": 0, \"D\": 4})\n", - "\n", - "\n", - "def get_indices_with_value(s: pd.Series, value):\n", - " \"\"\"Return indices for with the value is true\"\"\"\n", - " return s[s == value].index\n", - "\n", - "\n", - "get_indices_with_value(test_series, 4)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Boolean Indexing, remember to set\n", - "[parantheses](https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "MIN_AA_IN_SEQ = 10\n", - "MAX_AA_IN_SEQ = 2000\n", - "mask_min = d_seq_length < MIN_AA_IN_SEQ\n", - "mask_max = d_seq_length > MAX_AA_IN_SEQ\n", - "# _summary_text += f\"\\nThe FASTA file contain {sum(mask_min)} proteins with less than {MIN_AA_IN_SEQ} amino acids (AAs) and {sum(mask_max)} with more than {MAX_AA_IN_SEQ} AAs.\"\n", - "_summary_text += (\n", - " f\"The minimal AA sequence length is {min(d_seq_length)} of UniProt ID {', '.join(get_indices_with_value(d_seq_length, min(d_seq_length)))} \"\n", - " f\"and the maximal sequence lenght is {max(d_seq_length)} for UniProt ID {', '.join(get_indices_with_value(d_seq_length, max(d_seq_length)))}\"\n", - ")\n", - "print(_summary_text)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_ = d_seq_length.loc[(~mask_max)].to_frame(name=\"AA Seq Length\").plot.hist(bins=200)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "l_genes = []\n", - "n_set = 0\n", - "for _key, _data in data_fasta.items():\n", - " _gene_name = _data[KEY_GENE_NAME]\n", - " if _gene_name:\n", - " l_genes.append(_gene_name)\n", - " n_set += 1" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_summary_text += (\n", - " f\"\\nIn the FASTA header file {n_set} proteins have a set gene of a total of {len(data_fasta)} proteins,\"\n", - " f\" i.e. {len(data_fasta) - n_set} have an undefined origin. There are {len(set(l_genes))} unique gene names in the FASTA file specified.\\n\"\n", - ")\n", - "print(_summary_text)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "len(set(l_genes))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Number of well-defined peptides per protein (isotope)\n", - "\n", - "- well-defined peptides := no cleavage site is missed" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peps_exact_count_freq = defaultdict(int)\n", - "\n", - "for key, d_data in data_fasta.items():\n", - " _N = len(d_data[KEY_PEPTIDES][0])\n", - " # if _N == 0:\n", - " # print(key)\n", - " # print(d_data)\n", - " peps_exact_count_freq[_N] += 1\n", - "peps_exact_count_freq = pd.Series(dict(peps_exact_count_freq)).sort_index()\n", - "peps_exact_count_freq" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "n_first = 40\n", - "ax = peps_exact_count_freq.iloc[:n_first].plot(kind='bar',\n", - " figsize=(20, 5),\n", - " title=f'Frequency of number of exact peptides (up to {peps_exact_count_freq.iloc[:40].index[-1]})'\n", - " f' representing {peps_exact_count_freq.iloc[:40].sum()} proteins out of '\n", - " f'{peps_exact_count_freq.sum()} ({peps_exact_count_freq.iloc[:40].sum()/peps_exact_count_freq.sum():.2f}%)',\n", - " xlabel=\"Number of exact peptides (considered) in protein sequence\",\n", - " ylabel=\"Number of protein(s) (incl. isotopes)\",\n", - " fontsize=10)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peps_exact_count_freq = pd.Series(dict(peps_exact_count_freq)).sort_index()\n", - "fig = ax.get_figure()\n", - "fig.savefig(Path(FIGUREFOLDER) / 'fasta_exact_peptide_count_freq.png')\n", - "fig.savefig(Path(FIGUREFOLDER) / 'fasta_exact_peptide_count_freq.pdf')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Proteins' Isoforms" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Possible to join \"isoforms\" by joining all variants to one. Isoforms are\n", - "numbered from the second on by appending `-i` for $i>1$, i.e. starting\n", - "with `-2`. The gene name of which the protein (isoform) originate can be\n", - "obtained by using [id\n", - "mapping](https://www.uniprot.org/help/api_idmapping). Isoforms are not\n", - "mapped automatically by Uniprot to its GENENAME, i.e. you have to strip\n", - "all `-i`, e.g `-2`, `-3`, for querying. Here the protein, gene pairs are\n", - "mapped to the unique protein identifiers." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prot_ids = list(data_fasta.keys())\n", - "prot_ids = pd.Series(prot_ids)\n", - "prot_ids" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = prot_ids.str.contains(\"-\")\n", - "isoforms = prot_ids.copy().loc[mask]\n", - "isoforms" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "N_prot_with_isoform = isoforms.str.split(\"-\").str[0].nunique()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "n_unique_proteins_wo_isoforms = len(prot_ids) - len(isoforms)\n", - "_summary_text += \"\\nA total of {} proteins have at least one more isoform. \".format(\n", - " N_prot_with_isoform\n", - ")\n", - "_summary_text += f\"Collapsing isoforms into one protein results in {n_unique_proteins_wo_isoforms} proteins.\"\n", - "print(_summary_text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Remove Isoforms from list. How to integrate this information before?\n", - "\n", - "fasta-data has to be merge one-to-many." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "id_map = pd.DataFrame(\n", - " prot_ids.str.split(\"-\").str[0], columns=[\"protein\"]\n", - ") # , index=list(prot_ids))\n", - "id_map.index = pd.Index(prot_ids, name=\"prot_id\")\n", - "id_map" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "id_map.loc[id_map.index.str.contains(\"A0A096LP49|Q9Y6Z5|W5XKT8\")]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "l_proteins = id_map.protein.unique()\n", - "print(\n", - " f\"There are {len(l_proteins)} unique proteins without isoforms listed in the used fasta files.\"\n", - ")\n", - "# Check with pervious result.\n", - "assert n_unique_proteins_wo_isoforms == len(l_proteins)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "try:\n", - " with open(FN_PROT_GENE_MAP) as f:\n", - " dict_protein_to_gene = json.load(f)\n", - " logging.warning(f\"Loaded pre-cached map dict_protein_to_gene: {FN_PROT_GENE_MAP}\")\n", - "except FileNotFoundError:\n", - " dict_protein_to_gene = {}\n", - " start = 0\n", - " for end in list(range(10000, len(l_proteins), 10000)):\n", - " print(f\"Retrieve items {start+1:6} to {end:6}\")\n", - " _id_to_gene = query_uniprot_id_mapping(l_proteins[start:end])\n", - " print(f\"Found {len(_id_to_gene)} gene names\")\n", - " dict_protein_to_gene.update(_id_to_gene)\n", - " start = end\n", - " print(f\"Retrieve items {start:6} to {len(l_proteins):6}\")\n", - " _id_to_gene = query_uniprot_id_mapping(l_proteins[start:])\n", - " print(f\"Found {len(_id_to_gene)} gene names\")\n", - " dict_protein_to_gene.update(_id_to_gene)\n", - " with open(FN_PROT_GENE_MAP, \"w\") as f:\n", - " json.dump(dict_protein_to_gene, f, indent=4, sort_keys=False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "genes = pd.Series(dict_protein_to_gene, name=\"gene\")\n", - "genes" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "assert (\n", - " len(genes) == 72471\n", - "), f\"The number of proteins associated to a gene found on 11.11.2020 was 72471, now it's {len(genes)}\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Add gene names from UniProt to `id_map` DataFrame by an outer join\n", - "(keeping all information based on the protein names shared by isotopes)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "id_map = id_map.merge(genes, how=\"outer\", left_on=\"protein\", right_index=True)\n", - "id_map.sort_values(by=[\"gene\", \"protein\"], inplace=True)\n", - "id_map" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "id_map.replace('', np.nan)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Add the gene name collected previously from the Fasta Header" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "genes_fasta_offline = pd.DataFrame(\n", - " ((_key, _data[KEY_GENE_NAME]) for _key, _data in data_fasta.items()),\n", - " columns=[\"prot_id\", \"gene_fasta\"],\n", - ").set_index(\"prot_id\"\n", - " ).replace('', np.nan)\n", - "genes_fasta_offline.loc[genes_fasta_offline.gene_fasta.isna()]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "id_map = id_map.merge(\n", - " genes_fasta_offline,\n", - " how=\"outer\",\n", - " left_index=True,\n", - " right_index=True)\n", - "id_map.sort_values(by=[\"gene\", \"protein\"], inplace=True)\n", - "id_map" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask_no_gene = id_map.gene.isna()\n", - "id_map.loc[mask_no_gene]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Using the genes from the fasta file header reduces the number of missing\n", - "genes, but additionally other differences arise in the comparison to the\n", - "lastest version." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask_gene_diffs = id_map.gene != id_map.gene_fasta\n", - "id_map.loc[mask_gene_diffs]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "id_map.gene.isna().sum(), id_map.gene_fasta.isna()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "id_map.loc[(id_map.gene.isna()) & (id_map.gene_fasta.isna())]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_summary_text += (\n", - " f\"\\nThere are {id_map.gene.isna().sum()} protein IDs (or {id_map.loc[mask_no_gene].protein.nunique()} proteins) \"\n", - " \"without a gene associated to them in the current online version of UniProt, \"\n", - " f\"whereas there are no genes for only {id_map.gene_fasta.isna().sum()} in the headers of proteins in the used FASTA files.\"\n", - ")\n", - "print(_summary_text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Isotopes mapping\n", - "\n", - "Isotopes are mapped now to a protein with the same name. The same can be\n", - "achieved by just discarding everything behind the hypen `-`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "id_map.loc[id_map.index.str.contains(\"-\")]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Save id_map" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "id_map.to_json(FN_ID_MAP, orient=\"split\", indent=4)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Most proteins with a missing gene are deleted\n", - "\n", - "If one checks manually some of the examples (e.g. the hundred provided here), one sees that all are deleted from Uniprot.\n", - "\n", - "> How to obtain different versions of UniProt?!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "if not len(dict_protein_to_gene) == len(l_proteins):\n", - " print(\"Not all ids are mapped.\")\n", - " _diff = set(l_proteins).difference(dict_protein_to_gene.keys())\n", - " print(f\"Number of protein identifiers not mapped to a gene in UniProt online: {len(_diff)}\")\n", - " print(f'Look at {100} examples: {\", \".join(sample_iterable(_diff, 100))}')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_summary_text += (\n", - " f\"\\nMost of the {len(_diff)} proteins ({len(_diff)/len(l_proteins)*100:.2f} percent of the unique proteins) \"\n", - " \"not mapped to a gene name are deleted in the most current version of UniProt (online). \"\n", - " \"The versioning of the fasta-files has to be investigated, as there arise differences over time due to updates.\"\n", - ")\n", - "_summary_text += (\n", - " f\"\\nProteins are mapped to a total number of genes of {id_map.gene.nunique()} in the online UniProt version and {id_map.gene_fasta.nunique()} in the offline used one.\\n\"\n", - ")\n", - "print(_summary_text)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "f\"Proteins are mapped to a total number of genes of {len(set(dict_protein_to_gene.values()))}\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Map peptide to either identifier, common protein or gene\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptide_to_prot = defaultdict(list)\n", - "for _id, _data in tqdm(data_fasta.items()):\n", - " for _pep in iterFlatten(_data[\"peptides\"]):\n", - " peptide_to_prot[_pep].append(_id)\n", - "\n", - "_summary_text += f\"\\nConsidering {MAX_MISSED_CLEAVAGES} missed cleavage site(s) there are {len(peptide_to_prot):,d} unique peptides.\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(_summary_text)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "{_key: peptide_to_prot[_key] for _key in sample_iterable(peptide_to_prot.keys())}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "with open(FN_PEP_TO_PROT, \"w\") as f:\n", - " json.dump(peptide_to_prot, f, indent=4, sort_keys=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot histograms for different levels of abstraction\n", - "\n", - "Plot counts of matched\n", - " 1. protein IDs\n", - " 2. proteins (joining isoforms)\n", - " 3. genes\n", - "\n", - "to their peptides. See how many unique peptides exist. The number of\n", - "peptides should stay the same, so the counts do not have to be\n", - "normalized." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "USE_OFFLINE_FASTA_GENES = True\n", - "if USE_OFFLINE_FASTA_GENES:\n", - " dict_protein_to_gene = genes_fasta_offline.loc[~genes_fasta_offline.index.str.contains('-')]\n", - " dict_protein_to_gene = dict_protein_to_gene.dropna().to_dict()['gene_fasta']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "{_key: dict_protein_to_gene[_key] for _key in sample_iterable(dict_protein_to_gene.keys(), 10)}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "len(dict_protein_to_gene)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "counters = {}\n", - "levels = [\"protein_id\", \"protein\", \"gene\"]\n", - "for level in levels:\n", - " counters[level] = pd.Series(\n", - " count_peptide_matches(peptide_to_prot, dict_protein_to_gene, level=level)\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for level in levels:\n", - " print(f\"{level}: {counters[level]['AACLCFR']}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptide_to_prot[\"AACLCFR\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_prots = {x.split(\"-\")[0] for x in peptide_to_prot[\"AACLCFR\"]}\n", - "{dict_protein_to_gene[_prot] for _prot in _prots}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "counts_by_level = combine_value_counts(pd.DataFrame(counters))\n", - "counts_by_level = counts_by_level.replace(np.nan, 0).astype(int)\n", - "counts_by_level" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Interpretation: Peptides are assigned \\# of times to a protein_id, protein or gene respectively." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Check that for all levels the same number of peptides are counted." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "counts_by_level.sum()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Plot the frequency of matched proteins to one peptide sequence:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fig, ax = plt.subplots(figsize=(13, 7))\n", - "\n", - "ax = counts_by_level.iloc[:5].plot(kind=\"bar\", ax=ax)\n", - "ax.set_ylabel(\"peptide counts\")\n", - "ax.set_xlabel(\"number of matched levels\")\n", - "# ax.yaxis.set_major_formatter(\"{x:,}\")\n", - "_y_ticks = ax.set_yticks(list(range(0, 3_500_000, 500_000))) # is there a ways to transform float to int in matplotlib?\n", - "_y_ticks_labels = ax.set_yticklabels([f\"{x:,}\" for x in range(0, 3_500_000, 500_000)])\n", - "\n", - "_savefig(fig, folder=\"figures\", name=\"fasta_top4\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fig, axes = plt.subplots(2, 2, figsize=(17, 10))\n", - "axes = axes.flatten()\n", - "\n", - "counts_by_level.iloc[:10].plot(kind=\"bar\", ax=axes[0])\n", - "axes[0].set_title(\"up to 9 matches\")\n", - "axes[0].set_yticks(list(range(0, 3_500_000, 500_000)))\n", - "axes[0].set_yticklabels(['0', '500,000', '1,000,000', '1,500,000', '2,000,000', '2,500,000', '3,000,000'])\n", - "\n", - "_start = 10\n", - "for i, _end in enumerate([31, 61], start=1):\n", - " counts_by_level.iloc[_start:_end].plot(kind=\"bar\", ax=axes[i])\n", - " axes[i].set_title(f\"{_start} to {_end-1} matches\")\n", - " _start = _end\n", - "\n", - "i += 1\n", - "counts_by_level.iloc[-30:].plot(kind=\"bar\", ax=axes[i])\n", - "axes[i].set_title(f\"{30} most frequent matches\")\n", - "\n", - "\n", - "axes = axes.reshape((2, 2))\n", - "\n", - "pad = 5 # in point\n", - "for i in range(2):\n", - " axes[-1, i].set_xlabel(\"Count of number of matches for a peptide\")\n", - " axes[i, 0].set_ylabel(\"number of peptides\")\n", - "\n", - "_ = fig.suptitle(\n", - " \"Frequency of peptides matched to x items of protein IDs, proteins (combining isotopes) and genes\",\n", - " fontsize=16,\n", - ")\n", - "\n", - "\n", - "fig.tight_layout()\n", - "_savefig(fig, folder=\"figures\", name=\"fasta_mapping_counts\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "check for homology of sequences in python?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Create Automated report\n", - "\n", - "- paragraph in tex for report\n", - "- summary table" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(_summary_text)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "Path(SUMMARY_FILE).parent.mkdir(exist_ok=True)\n", - "with open(Path(SUMMARY_FILE), \"w\") as f:\n", - " f.write(_summary_text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Save mappings as JSON\n", - "\n", - "Each `protein_id` is an entry with the following information:\n", - "```\n", - "'meta': \n", - "'seq': \n", - "'peptides': \n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "with open(FN_FASTA_DB, \"w\") as f:\n", - " json.dump(data_fasta, f, indent=4, sort_keys=False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "os.stat(FN_FASTA_DB).st_size / 1024 / 1024" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13 (default, Mar 28 2022, 06:59:08) [MSC v.1916 64 bit (AMD64)]" - }, - "toc-autonumbering": true - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/misc_FASTA_tryptic_digest.py b/project/misc_FASTA_tryptic_digest.py deleted file mode 100644 index 58a49f179..000000000 --- a/project/misc_FASTA_tryptic_digest.py +++ /dev/null @@ -1,709 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: vaep -# language: python -# name: vaep -# --- - -# %% [markdown] -# # Process FASTA files -# > uses only the provided fasta files in `src.config.py` by `FOLDER_FASTA` -# -# - create theoretically considered peptides considered by search engines -# - dump results as human readable json to `FN_FASTA_DB` file specifed in src.config. -# -# > Based on notebook received by [Annelaura Bach](https://www.cpr.ku.dk/staff/mann-group/?pure=en/persons/443836) and created by Johannes B. Müller \[[scholar](https://scholar.google.com/citations?user=Rn1OS8oAAAAJ&hl=de), [MPI Biochemistry](https://www.biochem.mpg.de/person/93696/2253)\] - -# %% - -from collections import defaultdict, namedtuple -import os -import json -import logging -from pathlib import Path - -# import matplotlib -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd -from tqdm.notebook import tqdm - -# %% -from vaep.fasta import cleave_to_tryptic -from vaep.fasta import iterFlatten -from vaep.fasta import count_peptide_matches -from vaep.fasta import read_fasta -from vaep.io import search_files -from vaep.pandas import combine_value_counts -from vaep.databases.uniprot import query_uniprot_id_mapping -from vaep.utils import sample_iterable -from vaep.plotting import _savefig - -# %% -from config import FN_FASTA_DB -from config import FIGUREFOLDER -from config import FN_ID_MAP -from config import FN_PROT_GENE_MAP -from config import FN_PEP_TO_PROT - -from config import KEY_FASTA_HEADER, KEY_FASTA_SEQ, KEY_GENE_NAME, KEY_PEPTIDES - -# %% [markdown] -# ## Core Functionality - Example -# -# - write tests for core functinality -# - refactor to file - -# %% -test_data = { - "meta": ">tr|A0A024R1R8|A0A024R1R8_HUMAN HCG2014768, isoform CRA_a OS=Homo sapiens OX=9606 GN=hCG_2014768 PE=4 SV=1", - "seq": "MSSHEGGKKKALKQPKKQAKEMDEEEKAFKQKQKEEQKKLEVLKAKVVGKGPLATGGIKKSGKK", - "peptides": [ - "MSSHEGGK", - "EMDEEEK", - "GPLATGGIK"], -} - -# %% [markdown] -# regex is slower than native string replacing and splitting in Python - -# %% -# import re -# cut_by_trypsin = re.compile('([^K]+K)|([^R]+R)') -# _res = cut_by_trypsin.split(test_data['seq']) -# [_pep for _pep in _res if _pep != '' and _pep != None] - -# %% [markdown] -# -# - map peptide set of peptides (how to deal with mis-cleavages?) -# - mis-cleavages can happen both to the peptide before and after. -# > `pep1, pep2, pep3, pep4, pep5` -# > `pep1pep2, pep2pep3, pep3pep4, pep4pep5` -# - sliding windows can pass trough the list of peptides - should work with recursion - -# %% -l_peptides = test_data["seq"].replace("K", "K ").replace("R", "R ").split() -l_peptides - -# %% [markdown] -# `add_rxk` should add pattern of starting R and trailing K ? - -# %% -last_pep = "" -temp_peps = [] -num_missed_cleavages = 1 -add_rxk = True - -sec_last_pep = "" - -pep_rdx = [] - -for pep in l_peptides: - if last_pep != "": - temp_peps.append(last_pep + pep) - if add_rxk and sec_last_pep != "" and len(sec_last_pep) <= 2: - _pep_rxk = sec_last_pep + last_pep + pep - print(_pep_rxk) - pep_rdx.append(_pep_rxk) - temp_peps.append(_pep_rxk) - - sec_last_pep = last_pep # sec_last_pep, last_pep = last_pep, pep ? - last_pep = pep -temp_peps - -# %% -repr(pep_rdx) - -# %% [markdown] -# Missed cleavages core functionality (adapted) - -# %% -example_peptides_fasta = cleave_to_tryptic( - test_data["seq"], num_missed_cleavages=2, add_rxk=True -) -print("number of peptides: ", [len(_l) for _l in example_peptides_fasta]) -example_peptides_fasta[-1] - -# %% -print("".join(example_peptides_fasta[0]), *example_peptides_fasta, sep="\n") - -# %% [markdown] -# rdx peptides are a subset of two missed cleavage sites peptides. There -# are omitted when two and more cleavage site can be skipped. - -# %% -example_peptides_fasta = cleave_to_tryptic( - test_data["seq"], num_missed_cleavages=1, add_rxk=True -) -print("number of peptides: ", [len(_l) for _l in example_peptides_fasta]) -example_peptides_fasta[-1] - -# %% [markdown] -# Data Structure is no a list of list. Maybe this could be improved. -# Information what kind of type the peptide is from, is still interesting. - -# %% [markdown] -# ## Process Fasta Files -# -# First define input Folder and the file location of the created peptides: - -# %% -fasta_files = search_files(path=".", query=".fasta") -print(fasta_files) -print("\n".join(fasta_files.files)) - -# %% [markdown] -# ### Define Setup -# -# Set input FASTA, Output .txt name, lower legth cutoff, missed cleavages and if to report reverse. -# -# Tryptic digest of Fastas to Peptides >6 in list for matching with measured peptides - -# %% -CUTOFF_LEN_PEP = 7 -MAX_MISSED_CLEAVAGES = 2 # default in MaxQuant -DECOY_REVERSE = False -SUMMARY_FILE = "tex/fasta_tryptic_analysis.tex" - -_summary_text = ( - "The theoretical analysis of the fasta files gives an idea about how many possible peptides \n" - "can be expected by cleaving proteins using trypsin. The hyperparameters for peptide creation are \n" - f"to consider the minimal peptide length to be {CUTOFF_LEN_PEP} amino acids, \n" - f"to consider a maximum of {MAX_MISSED_CLEAVAGES} missed cleavage sites (default in MaxQuant) and \n" - f"to {'not ' if not DECOY_REVERSE else ''}add decoy peptides by reversing peptide sequences. \n" -) -print(_summary_text, sep="\n") - -# %% [markdown] -# From the [Fasta Meta information](https://ebi14.uniprot.org/help/fasta-headers) the Identifier is extracted. -# -# ``` -# >db|UniqueIdentifier|EntryName ProteinName OS=OrganismName OX=OrganismIdentifier [GN=GeneName ]PE=ProteinExistence SV=SequenceVersion -# ``` -# - db is `sp` for UniProtKB/Swiss-Prot and `tr` for UniProtKB/TrEMBL. -# - `UniqueIdentifier` is the primary *accession number* of the UniProtKB entry. (seems to be used by MQ) -# - `EntryName` is the entry name of the UniProtKB entry. -# - `ProteinName` is the recommended name of the UniProtKB entry as annotated in the *RecName* field. For UniProtKB/TrEMBL entries without a *RecName* field, the *SubName* field is used. In case of multiple SubNames, the first one is used. The 'precursor' attribute is excluded, 'Fragment' is included with the name if applicable. - -# %% [markdown] -# `>tr` or `>sp` - -# %% [markdown] -# ### Schema for single fasta entry - -# %% - - -data_fasta = {} - -# # add Schema? -# schema_fasta_entry = { -# KEY_FASTA_HEADER: str, -# KEY_GENE_NAME: str, -# KEY_FASTA_SEQ: str, -# KEY_PEPTIDES: (list, (2,2)) -# } -# # or dataclass -# from dataclasses import make_dataclass -# FastaEntry = make_dataclass(cls_name='FastaEntry', -# fields=[ -# (KEY_FASTA_HEADER, 'str'), -# (KEY_GENE_NAME, 'str'), -# (KEY_FASTA_SEQ, 'str'), -# (KEY_PEPTIDES, list) -# ]) -# # or namedtuple -# FastaEntry = namedtuple('FastaEntry', [KEY_FASTA_HEADER, KEY_GENE_NAME, KEY_FASTA_SEQ, KEY_PEPTIDES]) - -# %% [markdown] -# How to validate schema of fasta entry stored as dictionary? -# - [schema](https://stackoverflow.com/questions/45812387/how-to-validate-structure-or-schema-of-dictionary-in-python) validation in python discussion - -# %% [markdown] -# ### Process Fasta file - -# %% -for _fasta in tqdm(fasta_files.files): - - with open(_fasta) as fp: - for i, (metainfo, seq) in tqdm(enumerate(read_fasta(fp))): - identifier = metainfo.split("|")[1] - gene = "|".join([x.split("=")[-1] for x in metainfo.split() if "GN=" in x]) - if identifier in data_fasta: - raise ValueError("Key seen before: {}".format(identifier)) - _all_peptides = cleave_to_tryptic( - seq, num_missed_cleavages=MAX_MISSED_CLEAVAGES, reversed=DECOY_REVERSE - ) - data_fasta[identifier] = { - KEY_FASTA_HEADER: metainfo, - KEY_GENE_NAME: gene, - KEY_FASTA_SEQ: seq, - KEY_PEPTIDES: [ - [_pep for _pep in _peptides if len(_pep) >= CUTOFF_LEN_PEP] - for _peptides in _all_peptides - ], - } - -# %% [markdown] -# `fasta_data` holds all information to pick a subset of peptides from peptides intensity tables - -# %% -# from random import sample -# sample_ids = sample(list(data_fasta), 10) -# for _id in sample_ids: -# print("Unique Identifier: {}: \n\t AA-Seq: {} \n\t Header: {} \n\t Peptides: {}\n".format(_id, data_fasta[_id]['seq'], data_fasta[_id]['meta'], data_fasta[_id]['peptides'])) -data_fasta["A0A024R1R8"] - -# %% -d_seq_length = {} -for _key, _data in data_fasta.items(): - d_seq_length[_key] = len(_data[KEY_FASTA_SEQ]) - -# %% -d_seq_length = pd.Series(d_seq_length) -d_seq_length.describe() - -# %% -test_series = pd.Series({"A": 4, "B": 1, "C": 0, "D": 4}) - - -def get_indices_with_value(s: pd.Series, value): - """Return indices for with the value is true""" - return s[s == value].index - - -get_indices_with_value(test_series, 4) - -# %% [markdown] -# Boolean Indexing, remember to set -# [parantheses](https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#boolean-indexing) - -# %% -MIN_AA_IN_SEQ = 10 -MAX_AA_IN_SEQ = 2000 -mask_min = d_seq_length < MIN_AA_IN_SEQ -mask_max = d_seq_length > MAX_AA_IN_SEQ -# _summary_text += f"\nThe FASTA file contain {sum(mask_min)} proteins with less than {MIN_AA_IN_SEQ} amino acids (AAs) and {sum(mask_max)} with more than {MAX_AA_IN_SEQ} AAs." -_summary_text += ( - f"The minimal AA sequence length is {min(d_seq_length)} of UniProt ID {', '.join(get_indices_with_value(d_seq_length, min(d_seq_length)))} " - f"and the maximal sequence lenght is {max(d_seq_length)} for UniProt ID {', '.join(get_indices_with_value(d_seq_length, max(d_seq_length)))}" -) -print(_summary_text) - -# %% -_ = d_seq_length.loc[(~mask_max)].to_frame(name="AA Seq Length").plot.hist(bins=200) - -# %% -l_genes = [] -n_set = 0 -for _key, _data in data_fasta.items(): - _gene_name = _data[KEY_GENE_NAME] - if _gene_name: - l_genes.append(_gene_name) - n_set += 1 - -# %% -_summary_text += ( - f"\nIn the FASTA header file {n_set} proteins have a set gene of a total of {len(data_fasta)} proteins," - f" i.e. {len(data_fasta) - n_set} have an undefined origin. There are {len(set(l_genes))} unique gene names in the FASTA file specified.\n" -) -print(_summary_text) - -# %% -len(set(l_genes)) - -# %% [markdown] -# ## Number of well-defined peptides per protein (isotope) -# -# - well-defined peptides := no cleavage site is missed - -# %% -peps_exact_count_freq = defaultdict(int) - -for key, d_data in data_fasta.items(): - _N = len(d_data[KEY_PEPTIDES][0]) - # if _N == 0: - # print(key) - # print(d_data) - peps_exact_count_freq[_N] += 1 -peps_exact_count_freq = pd.Series(dict(peps_exact_count_freq)).sort_index() -peps_exact_count_freq - -# %% -n_first = 40 -ax = peps_exact_count_freq.iloc[:n_first].plot(kind='bar', - figsize=(20, 5), - title=f'Frequency of number of exact peptides (up to {peps_exact_count_freq.iloc[:40].index[-1]})' - f' representing {peps_exact_count_freq.iloc[:40].sum()} proteins out of ' - f'{peps_exact_count_freq.sum()} ({peps_exact_count_freq.iloc[:40].sum()/peps_exact_count_freq.sum():.2f}%)', - xlabel="Number of exact peptides (considered) in protein sequence", - ylabel="Number of protein(s) (incl. isotopes)", - fontsize=10) - -# %% -peps_exact_count_freq = pd.Series(dict(peps_exact_count_freq)).sort_index() -fig = ax.get_figure() -fig.savefig(Path(FIGUREFOLDER) / 'fasta_exact_peptide_count_freq.png') -fig.savefig(Path(FIGUREFOLDER) / 'fasta_exact_peptide_count_freq.pdf') - -# %% [markdown] -# ### Proteins' Isoforms - -# %% [markdown] -# Possible to join "isoforms" by joining all variants to one. Isoforms are -# numbered from the second on by appending `-i` for $i>1$, i.e. starting -# with `-2`. The gene name of which the protein (isoform) originate can be -# obtained by using [id -# mapping](https://www.uniprot.org/help/api_idmapping). Isoforms are not -# mapped automatically by Uniprot to its GENENAME, i.e. you have to strip -# all `-i`, e.g `-2`, `-3`, for querying. Here the protein, gene pairs are -# mapped to the unique protein identifiers. - -# %% -prot_ids = list(data_fasta.keys()) -prot_ids = pd.Series(prot_ids) -prot_ids - -# %% -mask = prot_ids.str.contains("-") -isoforms = prot_ids.copy().loc[mask] -isoforms - -# %% -N_prot_with_isoform = isoforms.str.split("-").str[0].nunique() - -# %% -n_unique_proteins_wo_isoforms = len(prot_ids) - len(isoforms) -_summary_text += "\nA total of {} proteins have at least one more isoform. ".format( - N_prot_with_isoform -) -_summary_text += f"Collapsing isoforms into one protein results in {n_unique_proteins_wo_isoforms} proteins." -print(_summary_text) - -# %% [markdown] -# Remove Isoforms from list. How to integrate this information before? -# -# fasta-data has to be merge one-to-many. - -# %% -id_map = pd.DataFrame( - prot_ids.str.split("-").str[0], columns=["protein"] -) # , index=list(prot_ids)) -id_map.index = pd.Index(prot_ids, name="prot_id") -id_map - -# %% -id_map.loc[id_map.index.str.contains("A0A096LP49|Q9Y6Z5|W5XKT8")] - -# %% -l_proteins = id_map.protein.unique() -print( - f"There are {len(l_proteins)} unique proteins without isoforms listed in the used fasta files." -) -# Check with pervious result. -assert n_unique_proteins_wo_isoforms == len(l_proteins) - -# %% -try: - with open(FN_PROT_GENE_MAP) as f: - dict_protein_to_gene = json.load(f) - logging.warning(f"Loaded pre-cached map dict_protein_to_gene: {FN_PROT_GENE_MAP}") -except FileNotFoundError: - dict_protein_to_gene = {} - start = 0 - for end in list(range(10000, len(l_proteins), 10000)): - print(f"Retrieve items {start+1:6} to {end:6}") - _id_to_gene = query_uniprot_id_mapping(l_proteins[start:end]) - print(f"Found {len(_id_to_gene)} gene names") - dict_protein_to_gene.update(_id_to_gene) - start = end - print(f"Retrieve items {start:6} to {len(l_proteins):6}") - _id_to_gene = query_uniprot_id_mapping(l_proteins[start:]) - print(f"Found {len(_id_to_gene)} gene names") - dict_protein_to_gene.update(_id_to_gene) - with open(FN_PROT_GENE_MAP, "w") as f: - json.dump(dict_protein_to_gene, f, indent=4, sort_keys=False) - -# %% -genes = pd.Series(dict_protein_to_gene, name="gene") -genes - -# %% -assert ( - len(genes) == 72471 -), f"The number of proteins associated to a gene found on 11.11.2020 was 72471, now it's {len(genes)}" - -# %% [markdown] -# Add gene names from UniProt to `id_map` DataFrame by an outer join -# (keeping all information based on the protein names shared by isotopes) - -# %% -id_map = id_map.merge(genes, how="outer", left_on="protein", right_index=True) -id_map.sort_values(by=["gene", "protein"], inplace=True) -id_map - -# %% -id_map.replace('', np.nan) - -# %% [markdown] -# Add the gene name collected previously from the Fasta Header - -# %% -genes_fasta_offline = pd.DataFrame( - ((_key, _data[KEY_GENE_NAME]) for _key, _data in data_fasta.items()), - columns=["prot_id", "gene_fasta"], -).set_index("prot_id" - ).replace('', np.nan) -genes_fasta_offline.loc[genes_fasta_offline.gene_fasta.isna()] - -# %% -id_map = id_map.merge( - genes_fasta_offline, - how="outer", - left_index=True, - right_index=True) -id_map.sort_values(by=["gene", "protein"], inplace=True) -id_map - -# %% -mask_no_gene = id_map.gene.isna() -id_map.loc[mask_no_gene] - -# %% [markdown] -# Using the genes from the fasta file header reduces the number of missing -# genes, but additionally other differences arise in the comparison to the -# lastest version. - -# %% -mask_gene_diffs = id_map.gene != id_map.gene_fasta -id_map.loc[mask_gene_diffs] - -# %% -id_map.gene.isna().sum(), id_map.gene_fasta.isna() - -# %% -id_map.loc[(id_map.gene.isna()) & (id_map.gene_fasta.isna())] - -# %% -_summary_text += ( - f"\nThere are {id_map.gene.isna().sum()} protein IDs (or {id_map.loc[mask_no_gene].protein.nunique()} proteins) " - "without a gene associated to them in the current online version of UniProt, " - f"whereas there are no genes for only {id_map.gene_fasta.isna().sum()} in the headers of proteins in the used FASTA files." -) -print(_summary_text) - -# %% [markdown] -# ### Isotopes mapping -# -# Isotopes are mapped now to a protein with the same name. The same can be -# achieved by just discarding everything behind the hypen `-` - -# %% -id_map.loc[id_map.index.str.contains("-")] - -# %% [markdown] -# Save id_map - -# %% -id_map.to_json(FN_ID_MAP, orient="split", indent=4) - -# %% [markdown] -# ### Most proteins with a missing gene are deleted -# -# If one checks manually some of the examples (e.g. the hundred provided here), one sees that all are deleted from Uniprot. -# -# > How to obtain different versions of UniProt?! - -# %% -if not len(dict_protein_to_gene) == len(l_proteins): - print("Not all ids are mapped.") - _diff = set(l_proteins).difference(dict_protein_to_gene.keys()) - print(f"Number of protein identifiers not mapped to a gene in UniProt online: {len(_diff)}") - print(f'Look at {100} examples: {", ".join(sample_iterable(_diff, 100))}') - -# %% -_summary_text += ( - f"\nMost of the {len(_diff)} proteins ({len(_diff)/len(l_proteins)*100:.2f} percent of the unique proteins) " - "not mapped to a gene name are deleted in the most current version of UniProt (online). " - "The versioning of the fasta-files has to be investigated, as there arise differences over time due to updates." -) -_summary_text += ( - f"\nProteins are mapped to a total number of genes of {id_map.gene.nunique()} in the online UniProt version and {id_map.gene_fasta.nunique()} in the offline used one.\n" -) -print(_summary_text) - -# %% -f"Proteins are mapped to a total number of genes of {len(set(dict_protein_to_gene.values()))}" - -# %% [markdown] -# ### Map peptide to either identifier, common protein or gene -# - -# %% -peptide_to_prot = defaultdict(list) -for _id, _data in tqdm(data_fasta.items()): - for _pep in iterFlatten(_data["peptides"]): - peptide_to_prot[_pep].append(_id) - -_summary_text += f"\nConsidering {MAX_MISSED_CLEAVAGES} missed cleavage site(s) there are {len(peptide_to_prot):,d} unique peptides." - -# %% -print(_summary_text) - -# %% -{_key: peptide_to_prot[_key] for _key in sample_iterable(peptide_to_prot.keys())} - -# %% -# %%time -with open(FN_PEP_TO_PROT, "w") as f: - json.dump(peptide_to_prot, f, indent=4, sort_keys=False) - -# %% [markdown] -# ### Plot histograms for different levels of abstraction -# -# Plot counts of matched -# 1. protein IDs -# 2. proteins (joining isoforms) -# 3. genes -# -# to their peptides. See how many unique peptides exist. The number of -# peptides should stay the same, so the counts do not have to be -# normalized. - -# %% -USE_OFFLINE_FASTA_GENES = True -if USE_OFFLINE_FASTA_GENES: - dict_protein_to_gene = genes_fasta_offline.loc[~genes_fasta_offline.index.str.contains('-')] - dict_protein_to_gene = dict_protein_to_gene.dropna().to_dict()['gene_fasta'] - -# %% -{_key: dict_protein_to_gene[_key] for _key in sample_iterable(dict_protein_to_gene.keys(), 10)} - -# %% -len(dict_protein_to_gene) - -# %% -counters = {} -levels = ["protein_id", "protein", "gene"] -for level in levels: - counters[level] = pd.Series( - count_peptide_matches(peptide_to_prot, dict_protein_to_gene, level=level) - ) - -# %% -for level in levels: - print(f"{level}: {counters[level]['AACLCFR']}") - -# %% -peptide_to_prot["AACLCFR"] - -# %% -_prots = {x.split("-")[0] for x in peptide_to_prot["AACLCFR"]} -{dict_protein_to_gene[_prot] for _prot in _prots} - -# %% -counts_by_level = combine_value_counts(pd.DataFrame(counters)) -counts_by_level = counts_by_level.replace(np.nan, 0).astype(int) -counts_by_level - -# %% [markdown] -# Interpretation: Peptides are assigned \# of times to a protein_id, protein or gene respectively. - -# %% [markdown] -# Check that for all levels the same number of peptides are counted. - -# %% -counts_by_level.sum() - -# %% [markdown] -# Plot the frequency of matched proteins to one peptide sequence: - -# %% -fig, ax = plt.subplots(figsize=(13, 7)) - -ax = counts_by_level.iloc[:5].plot(kind="bar", ax=ax) -ax.set_ylabel("peptide counts") -ax.set_xlabel("number of matched levels") -# ax.yaxis.set_major_formatter("{x:,}") -_y_ticks = ax.set_yticks(list(range(0, 3_500_000, 500_000))) # is there a ways to transform float to int in matplotlib? -_y_ticks_labels = ax.set_yticklabels([f"{x:,}" for x in range(0, 3_500_000, 500_000)]) - -_savefig(fig, folder="figures", name="fasta_top4") - -# %% -fig, axes = plt.subplots(2, 2, figsize=(17, 10)) -axes = axes.flatten() - -counts_by_level.iloc[:10].plot(kind="bar", ax=axes[0]) -axes[0].set_title("up to 9 matches") -axes[0].set_yticks(list(range(0, 3_500_000, 500_000))) -axes[0].set_yticklabels(['0', '500,000', '1,000,000', '1,500,000', '2,000,000', '2,500,000', '3,000,000']) - -_start = 10 -for i, _end in enumerate([31, 61], start=1): - counts_by_level.iloc[_start:_end].plot(kind="bar", ax=axes[i]) - axes[i].set_title(f"{_start} to {_end-1} matches") - _start = _end - -i += 1 -counts_by_level.iloc[-30:].plot(kind="bar", ax=axes[i]) -axes[i].set_title(f"{30} most frequent matches") - - -axes = axes.reshape((2, 2)) - -pad = 5 # in point -for i in range(2): - axes[-1, i].set_xlabel("Count of number of matches for a peptide") - axes[i, 0].set_ylabel("number of peptides") - -_ = fig.suptitle( - "Frequency of peptides matched to x items of protein IDs, proteins (combining isotopes) and genes", - fontsize=16, -) - - -fig.tight_layout() -_savefig(fig, folder="figures", name="fasta_mapping_counts") - -# %% [markdown] -# check for homology of sequences in python? - -# %% [markdown] -# ## Create Automated report -# -# - paragraph in tex for report -# - summary table - -# %% -print(_summary_text) - -# %% -Path(SUMMARY_FILE).parent.mkdir(exist_ok=True) -with open(Path(SUMMARY_FILE), "w") as f: - f.write(_summary_text) - -# %% [markdown] -# ## Save mappings as JSON -# -# Each `protein_id` is an entry with the following information: -# ``` -# 'meta': -# 'seq': -# 'peptides': -# ``` - -# %% -# %%time -with open(FN_FASTA_DB, "w") as f: - json.dump(data_fasta, f, indent=4, sort_keys=False) - -# %% -os.stat(FN_FASTA_DB).st_size / 1024 / 1024 diff --git a/project/misc_MaxQuantOutput.ipynb b/project/misc_MaxQuantOutput.ipynb deleted file mode 100644 index d855747e1..000000000 --- a/project/misc_MaxQuantOutput.ipynb +++ /dev/null @@ -1,2556 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# MaxQuantOutput" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "8016b389a5db4e868898f50e9e1987b9", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Dropdown(description='Select a folder', options=(WindowsPath('data/mq_out/20190611_QX3_LiSc_MA_Hela_500ng_LC15…" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from pathlib import Path\n", - "import ipywidgets as w\n", - "\n", - "import vaep.io as io\n", - "import vaep.io.mq as mq\n", - "\n", - "from config import FOLDER_MQ_TXT_DATA\n", - "\n", - "folders = io.search_subfolders(path=FOLDER_MQ_TXT_DATA, depth=1, exclude_root=True)\n", - "w_folder = w.Dropdown(options=folders, description='Select a folder')\n", - "w_folder" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## MaxQuantOutput class\n", - "\n", - "Instead of handling the files manually in a MQ folder, e.g. like" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "PathsList(files=['.ipynb_checkpoints', 'allPeptides.txt', 'evidence.txt', 'matchedFeatures.txt', 'modificationSpecificPeptides.txt', 'ms3Scans.txt', 'msms.txt', 'msmsScans.txt', 'mzRange.txt', 'parameters.txt', 'peptides.txt', 'proteinGroups.txt', 'summary.txt', 'tables.pdf'], folder=WindowsPath('data/mq_out/20190611_QX3_LiSc_MA_Hela_500ng_LC15'))" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "all_files = io.search_files(path=w_folder.value, query='')\n", - "all_files" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "files can just be accessed using the `MaxQuantOutput` class." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "MaxQuantOutput(WindowsPath('data/mq_out/20190611_QX3_LiSc_MA_Hela_500ng_LC15'))" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mq_output = mq.MaxQuantOutput(w_folder.value)\n", - "mq_output" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This lists the files in the current folder for you (calling `search_files`):" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['allPeptides.txt',\n", - " 'evidence.txt',\n", - " 'matchedFeatures.txt',\n", - " 'modificationSpecificPeptides.txt',\n", - " 'ms3Scans.txt',\n", - " 'msms.txt',\n", - " 'msmsScans.txt',\n", - " 'mzRange.txt',\n", - " 'parameters.txt',\n", - " 'peptides.txt',\n", - " 'proteinGroups.txt',\n", - " 'summary.txt']" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mq_output.files" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And extends the class attributes on intialization by the expected files (statically):" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['NAME_FILE_MAP',\n", - " 'dump_intensity',\n", - " 'find_attribute',\n", - " 'get_files',\n", - " 'get_list_of_attributes',\n", - " 'load',\n", - " 'register_file']" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mq_output._inital_attritubutes" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['NAME_FILE_MAP',\n", - " 'OxidationSites',\n", - " '_inital_attritubutes',\n", - " 'allPeptides',\n", - " 'dump_intensity',\n", - " 'evidence',\n", - " 'files',\n", - " 'find_attribute',\n", - " 'folder',\n", - " 'get_files',\n", - " 'get_list_of_attributes',\n", - " 'load',\n", - " 'matchedFeatures',\n", - " 'modificationSpecificPeptides',\n", - " 'ms3Scans',\n", - " 'msms',\n", - " 'msmsScans',\n", - " 'mzRange',\n", - " 'parameters',\n", - " 'paths',\n", - " 'peptides',\n", - " 'proteinGroups',\n", - " 'register_file',\n", - " 'summary']" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mq_output.get_list_of_attributes()" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# not able to delete yet. __getitem__ better alternative?\n", - "# lookup\n", - "# del mq_output.OxidationMSites" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'allPeptides': 'allPeptides.txt',\n", - " 'evidence': 'evidence.txt',\n", - " 'matchedFeatures': 'matchedFeatures.txt',\n", - " 'modificationSpecificPeptides': 'modificationSpecificPeptides.txt',\n", - " 'ms3Scans': 'ms3Scans.txt',\n", - " 'msms': 'msms.txt',\n", - " 'msmsScans': 'msmsScans.txt',\n", - " 'mzRange': 'mzRange.txt',\n", - " 'parameters': 'parameters.txt',\n", - " 'peptides': 'peptides.txt',\n", - " 'proteinGroups': 'proteinGroups.txt',\n", - " 'summary': 'summary.txt'}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "{Path(x).stem: x for x in mq_output.files}" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "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", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
N-term cleavage windowC-term cleavage windowAmino acid beforeFirst amino acidSecond amino acidSecond last amino acidLast amino acidAmino acid afterA CountR Count...Potential contaminantidProtein group IDsMod. peptide IDsEvidence IDsMS/MS IDsBest MS/MSOxidation (M) site IDsTaxonomy IDsMS/MS Count
Sequence
AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPGAVGER______________________________LSGPAEVGPGAVGERTPRKKEPPRASPPGGKAAERT191...NaN017740000.0NaN96061
AAAAAAAAAVSRTTSSRVLRGGRDRGRAAAAAAAAAVSRRRKRGRAAAAAAAAAVSRRRKAEYPRRRRSSPSRAASRR91...NaN12311111.0NaN96061
AAAAAAAGDSDSWDADAFSVEDPVRK______________________________SWDADAFSVEDPVRKVGGGGTAGGDRWEGEMAARKV91...NaN218772222.0NaN96061
AAAAAAALQAKTILRQARNHKLRVDKAAAAAAALQAKSDEKRVDKAAAAAAALQAKSDEKAAVAGKKPVVGKAAAKS80...NaN32461333;44.0NaN96062
AAAAAAGAASGLPGPVAQGLK______________________________GAASGLPGPVAQGLKEALVDTLTGILSPVQMAALKE90...NaN4416244;55;66.0NaN96062
..................................................................
YYTSASGDEMVSLKHEDSQNRKKLSELLRYYTSASGDEMVSLKDRYYTSASGDEMVSLKDYCTRMKENQKHIYYRYYLKD10...NaN38,783207740966;4096749202;49203;49204;49205;49206;49207;49208;4920954670;54671;54672;54673;54674;54675;54676;5467...54,679.01311960610
YYTVFDRDNNRPSGPLWILGDVFIGRYYTVFDRDNNRVGFAFIGRYYTVFDRDNNRVGFAEAARL______RYYNRV02...NaN38,78437940968492105468054,680.0NaN96061
YYVLNALKGQPVKVRVSYQKLLKYYVLNALKHRPPKAQSYQKLLKYYVLNALKHRPPKAQKKRYLFRSKYYLKH10...NaN38,785352140969492115468154,681.0NaN96061
YYVTIIDAPGHRGITIDISLWKFETSKYYVTIIDAPGHRDFITSKYYVTIIDAPGHRDFIKNMITGTSQADCKYYHRD11...NaN38,78628734097049212;49213;4921454682;54683;54684;54685;5468654,683.0NaN96065
YYYIPQYKREVKEHVGTDQFGNKYYYIPQYKNWRGQTITDQFGNKYYYIPQYKNWRGQTIREKRIVEAKYYYKN00...NaN38,787374540971492155468754,687.0NaN96061
\n", - "

38788 rows × 56 columns

\n", - "
" - ], - "text/plain": [ - " N-term cleavage window \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... ______________________________ \n", - "AAAAAAAAAVSR TTSSRVLRGGRDRGRAAAAAAAAAVSRRRK \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK ______________________________ \n", - "AAAAAAALQAK TILRQARNHKLRVDKAAAAAAALQAKSDEK \n", - "AAAAAAGAASGLPGPVAQGLK ______________________________ \n", - "... ... \n", - "YYTSASGDEMVSLK HEDSQNRKKLSELLRYYTSASGDEMVSLKD \n", - "YYTVFDRDNNR PSGPLWILGDVFIGRYYTVFDRDNNRVGFA \n", - "YYVLNALK GQPVKVRVSYQKLLKYYVLNALKHRPPKAQ \n", - "YYVTIIDAPGHR GITIDISLWKFETSKYYVTIIDAPGHRDFI \n", - "YYYIPQYK REVKEHVGTDQFGNKYYYIPQYKNWRGQTI \n", - "\n", - " C-term cleavage window \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... LSGPAEVGPGAVGERTPRKKEPPRASPPGG \n", - "AAAAAAAAAVSR RGRAAAAAAAAAVSRRRKAEYPRRRRSSPS \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK SWDADAFSVEDPVRKVGGGGTAGGDRWEGE \n", - "AAAAAAALQAK RVDKAAAAAAALQAKSDEKAAVAGKKPVVG \n", - "AAAAAAGAASGLPGPVAQGLK GAASGLPGPVAQGLKEALVDTLTGILSPVQ \n", - "... ... \n", - "YYTSASGDEMVSLK RYYTSASGDEMVSLKDYCTRMKENQKHIYY \n", - "YYTVFDRDNNR FIGRYYTVFDRDNNRVGFAEAARL______ \n", - "YYVLNALK SYQKLLKYYVLNALKHRPPKAQKKRYLFRS \n", - "YYVTIIDAPGHR TSKYYVTIIDAPGHRDFIKNMITGTSQADC \n", - "YYYIPQYK TDQFGNKYYYIPQYKNWRGQTIREKRIVEA \n", - "\n", - " Amino acid before \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... K \n", - "AAAAAAAAAVSR R \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK M \n", - "AAAAAAALQAK K \n", - "AAAAAAGAASGLPGPVAQGLK M \n", - "... ... \n", - "YYTSASGDEMVSLK R \n", - "YYTVFDRDNNR R \n", - "YYVLNALK K \n", - "YYVTIIDAPGHR K \n", - "YYYIPQYK K \n", - "\n", - " First amino acid \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... A \n", - "AAAAAAAAAVSR A \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK A \n", - "AAAAAAALQAK A \n", - "AAAAAAGAASGLPGPVAQGLK A \n", - "... ... \n", - "YYTSASGDEMVSLK Y \n", - "YYTVFDRDNNR Y \n", - "YYVLNALK Y \n", - "YYVTIIDAPGHR Y \n", - "YYYIPQYK Y \n", - "\n", - " Second amino acid \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... A \n", - "AAAAAAAAAVSR A \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK A \n", - "AAAAAAALQAK A \n", - "AAAAAAGAASGLPGPVAQGLK A \n", - "... ... \n", - "YYTSASGDEMVSLK Y \n", - "YYTVFDRDNNR Y \n", - "YYVLNALK Y \n", - "YYVTIIDAPGHR Y \n", - "YYYIPQYK Y \n", - "\n", - " Second last amino acid \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... E \n", - "AAAAAAAAAVSR S \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK R \n", - "AAAAAAALQAK A \n", - "AAAAAAGAASGLPGPVAQGLK L \n", - "... ... \n", - "YYTSASGDEMVSLK L \n", - "YYTVFDRDNNR N \n", - "YYVLNALK L \n", - "YYVTIIDAPGHR H \n", - "YYYIPQYK Y \n", - "\n", - " Last amino acid \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... R \n", - "AAAAAAAAAVSR R \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK K \n", - "AAAAAAALQAK K \n", - "AAAAAAGAASGLPGPVAQGLK K \n", - "... ... \n", - "YYTSASGDEMVSLK K \n", - "YYTVFDRDNNR R \n", - "YYVLNALK K \n", - "YYVTIIDAPGHR R \n", - "YYYIPQYK K \n", - "\n", - " Amino acid after A Count \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... T 19 \n", - "AAAAAAAAAVSR R 9 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK V 9 \n", - "AAAAAAALQAK S 8 \n", - "AAAAAAGAASGLPGPVAQGLK E 9 \n", - "... ... ... \n", - "YYTSASGDEMVSLK D 1 \n", - "YYTVFDRDNNR V 0 \n", - "YYVLNALK H 1 \n", - "YYVTIIDAPGHR D 1 \n", - "YYYIPQYK N 0 \n", - "\n", - " R Count ... \\\n", - "Sequence ... \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 1 ... \n", - "AAAAAAAAAVSR 1 ... \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 1 ... \n", - "AAAAAAALQAK 0 ... \n", - "AAAAAAGAASGLPGPVAQGLK 0 ... \n", - "... ... ... \n", - "YYTSASGDEMVSLK 0 ... \n", - "YYTVFDRDNNR 2 ... \n", - "YYVLNALK 0 ... \n", - "YYVTIIDAPGHR 1 ... \n", - "YYYIPQYK 0 ... \n", - "\n", - " Potential contaminant \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... NaN \n", - "AAAAAAAAAVSR NaN \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK NaN \n", - "AAAAAAALQAK NaN \n", - "AAAAAAGAASGLPGPVAQGLK NaN \n", - "... ... \n", - "YYTSASGDEMVSLK NaN \n", - "YYTVFDRDNNR NaN \n", - "YYVLNALK NaN \n", - "YYVTIIDAPGHR NaN \n", - "YYYIPQYK NaN \n", - "\n", - " id Protein group IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 1774 \n", - "AAAAAAAAAVSR 1 231 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2 1877 \n", - "AAAAAAALQAK 3 2461 \n", - "AAAAAAGAASGLPGPVAQGLK 4 4162 \n", - "... ... ... \n", - "YYTSASGDEMVSLK 38,783 2077 \n", - "YYTVFDRDNNR 38,784 379 \n", - "YYVLNALK 38,785 3521 \n", - "YYVTIIDAPGHR 38,786 2873 \n", - "YYYIPQYK 38,787 3745 \n", - "\n", - " Mod. peptide IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2 \n", - "AAAAAAALQAK 3 \n", - "AAAAAAGAASGLPGPVAQGLK 4 \n", - "... ... \n", - "YYTSASGDEMVSLK 40966;40967 \n", - "YYTVFDRDNNR 40968 \n", - "YYVLNALK 40969 \n", - "YYVTIIDAPGHR 40970 \n", - "YYYIPQYK 40971 \n", - "\n", - " Evidence IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2 \n", - "AAAAAAALQAK 3 \n", - "AAAAAAGAASGLPGPVAQGLK 4;5 \n", - "... ... \n", - "YYTSASGDEMVSLK 49202;49203;49204;49205;49206;49207;49208;49209 \n", - "YYTVFDRDNNR 49210 \n", - "YYVLNALK 49211 \n", - "YYVTIIDAPGHR 49212;49213;49214 \n", - "YYYIPQYK 49215 \n", - "\n", - " MS/MS IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2 \n", - "AAAAAAALQAK 3;4 \n", - "AAAAAAGAASGLPGPVAQGLK 5;6 \n", - "... ... \n", - "YYTSASGDEMVSLK 54670;54671;54672;54673;54674;54675;54676;5467... \n", - "YYTVFDRDNNR 54680 \n", - "YYVLNALK 54681 \n", - "YYVTIIDAPGHR 54682;54683;54684;54685;54686 \n", - "YYYIPQYK 54687 \n", - "\n", - " Best MS/MS \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0.0 \n", - "AAAAAAAAAVSR 1.0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2.0 \n", - "AAAAAAALQAK 4.0 \n", - "AAAAAAGAASGLPGPVAQGLK 6.0 \n", - "... ... \n", - "YYTSASGDEMVSLK 54,679.0 \n", - "YYTVFDRDNNR 54,680.0 \n", - "YYVLNALK 54,681.0 \n", - "YYVTIIDAPGHR 54,683.0 \n", - "YYYIPQYK 54,687.0 \n", - "\n", - " Oxidation (M) site IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... NaN \n", - "AAAAAAAAAVSR NaN \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK NaN \n", - "AAAAAAALQAK NaN \n", - "AAAAAAGAASGLPGPVAQGLK NaN \n", - "... ... \n", - "YYTSASGDEMVSLK 1311 \n", - "YYTVFDRDNNR NaN \n", - "YYVLNALK NaN \n", - "YYVTIIDAPGHR NaN \n", - "YYYIPQYK NaN \n", - "\n", - " Taxonomy IDs MS/MS Count \n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 9606 1 \n", - "AAAAAAAAAVSR 9606 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 9606 1 \n", - "AAAAAAALQAK 9606 2 \n", - "AAAAAAGAASGLPGPVAQGLK 9606 2 \n", - "... ... ... \n", - "YYTSASGDEMVSLK 9606 10 \n", - "YYTVFDRDNNR 9606 1 \n", - "YYVLNALK 9606 1 \n", - "YYVTIIDAPGHR 9606 5 \n", - "YYYIPQYK 9606 1 \n", - "\n", - "[38788 rows x 56 columns]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# mq_output.evidence(mq_output)\n", - "mq_output.peptides" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Dynamic Attribute lookup\n", - "\n", - "try to use `__getattr__`, maybe `__setattr__`?\n", - "\n", - "This version offers less inspection possibilities as the attributes are only set when they are looked up." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "MaxQuantOutputDynamic(WindowsPath('data/mq_out/20190611_QX3_LiSc_MA_Hela_500ng_LC15'))" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mq_output = mq.MaxQuantOutputDynamic(w_folder.value)\n", - "mq_output" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['allPeptides',\n", - " 'evidence',\n", - " 'matchedFeatures',\n", - " 'modificationSpecificPeptides',\n", - " 'ms3Scans',\n", - " 'msms',\n", - " 'msmsScans',\n", - " 'mzRange',\n", - " 'parameters',\n", - " 'peptides',\n", - " 'proteinGroups',\n", - " 'summary']" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mq_output.file_keys" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "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", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
N-term cleavage windowC-term cleavage windowAmino acid beforeFirst amino acidSecond amino acidSecond last amino acidLast amino acidAmino acid afterA CountR Count...Potential contaminantidProtein group IDsMod. peptide IDsEvidence IDsMS/MS IDsBest MS/MSOxidation (M) site IDsTaxonomy IDsMS/MS Count
Sequence
AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPGAVGER______________________________LSGPAEVGPGAVGERTPRKKEPPRASPPGGKAAERT191...NaN017740000.0NaN96061
AAAAAAAAAVSRTTSSRVLRGGRDRGRAAAAAAAAAVSRRRKRGRAAAAAAAAAVSRRRKAEYPRRRRSSPSRAASRR91...NaN12311111.0NaN96061
AAAAAAAGDSDSWDADAFSVEDPVRK______________________________SWDADAFSVEDPVRKVGGGGTAGGDRWEGEMAARKV91...NaN218772222.0NaN96061
AAAAAAALQAKTILRQARNHKLRVDKAAAAAAALQAKSDEKRVDKAAAAAAALQAKSDEKAAVAGKKPVVGKAAAKS80...NaN32461333;44.0NaN96062
AAAAAAGAASGLPGPVAQGLK______________________________GAASGLPGPVAQGLKEALVDTLTGILSPVQMAALKE90...NaN4416244;55;66.0NaN96062
..................................................................
YYTSASGDEMVSLKHEDSQNRKKLSELLRYYTSASGDEMVSLKDRYYTSASGDEMVSLKDYCTRMKENQKHIYYRYYLKD10...NaN38,783207740966;4096749202;49203;49204;49205;49206;49207;49208;4920954670;54671;54672;54673;54674;54675;54676;5467...54,679.01311960610
YYTVFDRDNNRPSGPLWILGDVFIGRYYTVFDRDNNRVGFAFIGRYYTVFDRDNNRVGFAEAARL______RYYNRV02...NaN38,78437940968492105468054,680.0NaN96061
YYVLNALKGQPVKVRVSYQKLLKYYVLNALKHRPPKAQSYQKLLKYYVLNALKHRPPKAQKKRYLFRSKYYLKH10...NaN38,785352140969492115468154,681.0NaN96061
YYVTIIDAPGHRGITIDISLWKFETSKYYVTIIDAPGHRDFITSKYYVTIIDAPGHRDFIKNMITGTSQADCKYYHRD11...NaN38,78628734097049212;49213;4921454682;54683;54684;54685;5468654,683.0NaN96065
YYYIPQYKREVKEHVGTDQFGNKYYYIPQYKNWRGQTITDQFGNKYYYIPQYKNWRGQTIREKRIVEAKYYYKN00...NaN38,787374540971492155468754,687.0NaN96061
\n", - "

38788 rows × 56 columns

\n", - "
" - ], - "text/plain": [ - " N-term cleavage window \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... ______________________________ \n", - "AAAAAAAAAVSR TTSSRVLRGGRDRGRAAAAAAAAAVSRRRK \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK ______________________________ \n", - "AAAAAAALQAK TILRQARNHKLRVDKAAAAAAALQAKSDEK \n", - "AAAAAAGAASGLPGPVAQGLK ______________________________ \n", - "... ... \n", - "YYTSASGDEMVSLK HEDSQNRKKLSELLRYYTSASGDEMVSLKD \n", - "YYTVFDRDNNR PSGPLWILGDVFIGRYYTVFDRDNNRVGFA \n", - "YYVLNALK GQPVKVRVSYQKLLKYYVLNALKHRPPKAQ \n", - "YYVTIIDAPGHR GITIDISLWKFETSKYYVTIIDAPGHRDFI \n", - "YYYIPQYK REVKEHVGTDQFGNKYYYIPQYKNWRGQTI \n", - "\n", - " C-term cleavage window \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... LSGPAEVGPGAVGERTPRKKEPPRASPPGG \n", - "AAAAAAAAAVSR RGRAAAAAAAAAVSRRRKAEYPRRRRSSPS \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK SWDADAFSVEDPVRKVGGGGTAGGDRWEGE \n", - "AAAAAAALQAK RVDKAAAAAAALQAKSDEKAAVAGKKPVVG \n", - "AAAAAAGAASGLPGPVAQGLK GAASGLPGPVAQGLKEALVDTLTGILSPVQ \n", - "... ... \n", - "YYTSASGDEMVSLK RYYTSASGDEMVSLKDYCTRMKENQKHIYY \n", - "YYTVFDRDNNR FIGRYYTVFDRDNNRVGFAEAARL______ \n", - "YYVLNALK SYQKLLKYYVLNALKHRPPKAQKKRYLFRS \n", - "YYVTIIDAPGHR TSKYYVTIIDAPGHRDFIKNMITGTSQADC \n", - "YYYIPQYK TDQFGNKYYYIPQYKNWRGQTIREKRIVEA \n", - "\n", - " Amino acid before \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... K \n", - "AAAAAAAAAVSR R \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK M \n", - "AAAAAAALQAK K \n", - "AAAAAAGAASGLPGPVAQGLK M \n", - "... ... \n", - "YYTSASGDEMVSLK R \n", - "YYTVFDRDNNR R \n", - "YYVLNALK K \n", - "YYVTIIDAPGHR K \n", - "YYYIPQYK K \n", - "\n", - " First amino acid \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... A \n", - "AAAAAAAAAVSR A \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK A \n", - "AAAAAAALQAK A \n", - "AAAAAAGAASGLPGPVAQGLK A \n", - "... ... \n", - "YYTSASGDEMVSLK Y \n", - "YYTVFDRDNNR Y \n", - "YYVLNALK Y \n", - "YYVTIIDAPGHR Y \n", - "YYYIPQYK Y \n", - "\n", - " Second amino acid \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... A \n", - "AAAAAAAAAVSR A \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK A \n", - "AAAAAAALQAK A \n", - "AAAAAAGAASGLPGPVAQGLK A \n", - "... ... \n", - "YYTSASGDEMVSLK Y \n", - "YYTVFDRDNNR Y \n", - "YYVLNALK Y \n", - "YYVTIIDAPGHR Y \n", - "YYYIPQYK Y \n", - "\n", - " Second last amino acid \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... E \n", - "AAAAAAAAAVSR S \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK R \n", - "AAAAAAALQAK A \n", - "AAAAAAGAASGLPGPVAQGLK L \n", - "... ... \n", - "YYTSASGDEMVSLK L \n", - "YYTVFDRDNNR N \n", - "YYVLNALK L \n", - "YYVTIIDAPGHR H \n", - "YYYIPQYK Y \n", - "\n", - " Last amino acid \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... R \n", - "AAAAAAAAAVSR R \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK K \n", - "AAAAAAALQAK K \n", - "AAAAAAGAASGLPGPVAQGLK K \n", - "... ... \n", - "YYTSASGDEMVSLK K \n", - "YYTVFDRDNNR R \n", - "YYVLNALK K \n", - "YYVTIIDAPGHR R \n", - "YYYIPQYK K \n", - "\n", - " Amino acid after A Count \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... T 19 \n", - "AAAAAAAAAVSR R 9 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK V 9 \n", - "AAAAAAALQAK S 8 \n", - "AAAAAAGAASGLPGPVAQGLK E 9 \n", - "... ... ... \n", - "YYTSASGDEMVSLK D 1 \n", - "YYTVFDRDNNR V 0 \n", - "YYVLNALK H 1 \n", - "YYVTIIDAPGHR D 1 \n", - "YYYIPQYK N 0 \n", - "\n", - " R Count ... \\\n", - "Sequence ... \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 1 ... \n", - "AAAAAAAAAVSR 1 ... \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 1 ... \n", - "AAAAAAALQAK 0 ... \n", - "AAAAAAGAASGLPGPVAQGLK 0 ... \n", - "... ... ... \n", - "YYTSASGDEMVSLK 0 ... \n", - "YYTVFDRDNNR 2 ... \n", - "YYVLNALK 0 ... \n", - "YYVTIIDAPGHR 1 ... \n", - "YYYIPQYK 0 ... \n", - "\n", - " Potential contaminant \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... NaN \n", - "AAAAAAAAAVSR NaN \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK NaN \n", - "AAAAAAALQAK NaN \n", - "AAAAAAGAASGLPGPVAQGLK NaN \n", - "... ... \n", - "YYTSASGDEMVSLK NaN \n", - "YYTVFDRDNNR NaN \n", - "YYVLNALK NaN \n", - "YYVTIIDAPGHR NaN \n", - "YYYIPQYK NaN \n", - "\n", - " id Protein group IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 1774 \n", - "AAAAAAAAAVSR 1 231 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2 1877 \n", - "AAAAAAALQAK 3 2461 \n", - "AAAAAAGAASGLPGPVAQGLK 4 4162 \n", - "... ... ... \n", - "YYTSASGDEMVSLK 38,783 2077 \n", - "YYTVFDRDNNR 38,784 379 \n", - "YYVLNALK 38,785 3521 \n", - "YYVTIIDAPGHR 38,786 2873 \n", - "YYYIPQYK 38,787 3745 \n", - "\n", - " Mod. peptide IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2 \n", - "AAAAAAALQAK 3 \n", - "AAAAAAGAASGLPGPVAQGLK 4 \n", - "... ... \n", - "YYTSASGDEMVSLK 40966;40967 \n", - "YYTVFDRDNNR 40968 \n", - "YYVLNALK 40969 \n", - "YYVTIIDAPGHR 40970 \n", - "YYYIPQYK 40971 \n", - "\n", - " Evidence IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2 \n", - "AAAAAAALQAK 3 \n", - "AAAAAAGAASGLPGPVAQGLK 4;5 \n", - "... ... \n", - "YYTSASGDEMVSLK 49202;49203;49204;49205;49206;49207;49208;49209 \n", - "YYTVFDRDNNR 49210 \n", - "YYVLNALK 49211 \n", - "YYVTIIDAPGHR 49212;49213;49214 \n", - "YYYIPQYK 49215 \n", - "\n", - " MS/MS IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2 \n", - "AAAAAAALQAK 3;4 \n", - "AAAAAAGAASGLPGPVAQGLK 5;6 \n", - "... ... \n", - "YYTSASGDEMVSLK 54670;54671;54672;54673;54674;54675;54676;5467... \n", - "YYTVFDRDNNR 54680 \n", - "YYVLNALK 54681 \n", - "YYVTIIDAPGHR 54682;54683;54684;54685;54686 \n", - "YYYIPQYK 54687 \n", - "\n", - " Best MS/MS \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0.0 \n", - "AAAAAAAAAVSR 1.0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2.0 \n", - "AAAAAAALQAK 4.0 \n", - "AAAAAAGAASGLPGPVAQGLK 6.0 \n", - "... ... \n", - "YYTSASGDEMVSLK 54,679.0 \n", - "YYTVFDRDNNR 54,680.0 \n", - "YYVLNALK 54,681.0 \n", - "YYVTIIDAPGHR 54,683.0 \n", - "YYYIPQYK 54,687.0 \n", - "\n", - " Oxidation (M) site IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... NaN \n", - "AAAAAAAAAVSR NaN \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK NaN \n", - "AAAAAAALQAK NaN \n", - "AAAAAAGAASGLPGPVAQGLK NaN \n", - "... ... \n", - "YYTSASGDEMVSLK 1311 \n", - "YYTVFDRDNNR NaN \n", - "YYVLNALK NaN \n", - "YYVTIIDAPGHR NaN \n", - "YYYIPQYK NaN \n", - "\n", - " Taxonomy IDs MS/MS Count \n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 9606 1 \n", - "AAAAAAAAAVSR 9606 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 9606 1 \n", - "AAAAAAALQAK 9606 2 \n", - "AAAAAAGAASGLPGPVAQGLK 9606 2 \n", - "... ... ... \n", - "YYTSASGDEMVSLK 9606 10 \n", - "YYTVFDRDNNR 9606 1 \n", - "YYVLNALK 9606 1 \n", - "YYVTIIDAPGHR 9606 5 \n", - "YYYIPQYK 9606 1 \n", - "\n", - "[38788 rows x 56 columns]" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mq_output.peptides" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "No such file: peptides_.txt: Choose one of the following:\n", - "allPeptides, evidence, matchedFeatures, modificationSpecificPeptides, ms3Scans, msms, msmsScans, mzRange, parameters, peptides, proteinGroups, summary\n" - ] - } - ], - "source": [ - "try:\n", - " mq_output.peptides_\n", - "except AttributeError as e:\n", - " print(*e.args)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['NAME_FILE_MAP',\n", - " 'OxidationSites',\n", - " '_inital_attritubutes',\n", - " '_peptides',\n", - " 'allPeptides',\n", - " 'dump_intensity',\n", - " 'evidence',\n", - " 'file_keys',\n", - " 'files',\n", - " 'find_attribute',\n", - " 'folder',\n", - " 'get_files',\n", - " 'get_list_of_attributes',\n", - " 'load',\n", - " 'matchedFeatures',\n", - " 'modificationSpecificPeptides',\n", - " 'ms3Scans',\n", - " 'msms',\n", - " 'msmsScans',\n", - " 'mzRange',\n", - " 'name_file_map',\n", - " 'parameters',\n", - " 'paths',\n", - " 'peptides',\n", - " 'proteinGroups',\n", - " 'register_file',\n", - " 'summary']" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mq_output.get_list_of_attributes()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Files" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### evidence.txt\n", - "\n", - "> some columns throw a warning" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\users\\kzl465\\documents\\repos\\vaep\\vaep\\io\\mq.py:87: DtypeWarning: Columns (50,53,58) have mixed types.Specify dtype option on import or set low_memory=False.\n", - " return cls.find_attribute(f'_{filename}')\n" - ] - }, - { - "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", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
LengthModificationsModified sequenceOxidation (M) ProbabilitiesOxidation (M) Score DiffsAcetyl (Protein N-term)Oxidation (M)Missed cleavagesProteinsLeading proteinsLeading razor proteinGene namesProtein namesTypeRaw fileMS/MS m/zChargem/zMassUncalibrated - Calibrated m/z [ppm]Uncalibrated - Calibrated m/z [Da]Mass error [ppm]Mass error [Da]Uncalibrated mass error [ppm]Uncalibrated mass error [Da]Max intensity m/z 0Retention timeRetention lengthCalibrated retention timeCalibrated retention time startCalibrated retention time finishRetention time calibrationMatch time differenceMatch m/z differenceMatch q-valueMatch scoreNumber of data pointsNumber of scansNumber of isotopic peaksPIFFraction of total spectrumBase peak fractionPEPMS/MS countMS/MS scan numberScoreDelta scoreCombinatoricsIntensityReversePotential contaminantidProtein group IDsPeptide IDMod. peptide IDMS/MS IDsBest MS/MSOxidation (M) site IDsTaxonomy IDs
Sequence
AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPGAVGER52Unmodified_AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVG...NaNNaN000R4GMQ1;O60341;O60341-2R4GMQ1R4GMQ1KDM1ALysine-specific histone demethylase 1AMULTI-MSMS20190611_QX3_LiSc_MA_Hela_500ng_LC151,101.841,101.34,401.12.40.00.20.02.60.01,101.885.60.385.685.585.80.0nannannannan84.022.05.00000.01106,834102.791.3157,739,000.0NaNNaN017740000NaN9606
AAAAAAAAAVSR12Unmodified_AAAAAAAAAVSR_NaNNaN000A0A0A6YYC7;Q96JP5-2;Q96JP5A0A0A6YYC7A0A0A6YYC7ZFP91-CNTF;ZFP91E3 ubiquitin-protein ligase ZFP91MULTI-MSMS20190611_QX3_LiSc_MA_Hela_500ng_LC15500.82500.8999.51.40.00.50.02.00.0500.825.60.225.625.425.60.0nannannannan37.016.03.00000.0130,18468.646.9187,575,000.0NaNNaN12311111NaN9606
AAAAAAAGDSDSWDADAFSVEDPVRK26Acetyl (Protein N-term)_(Acetyl (Protein N-term))AAAAAAAGDSDSWDADAFSV...NaNNaN101O75822;O75822-3;O75822-2O75822O75822EIF3JEukaryotic translation initiation factor 3 sub...MULTI-MSMS20190611_QX3_LiSc_MA_Hela_500ng_LC15879.43879.12,634.22.20.0-0.8-0.01.40.0879.495.00.695.094.795.30.0nannannannan157.047.05.00000.01118,493157.9144.31442,780,000.0NaNNaN218772222NaN9606
AAAAAAALQAK11Unmodified_AAAAAAALQAK_NaNNaN000P36578;H3BM89;H3BU31P36578P36578RPL460S ribosomal protein L4MULTI-MSMS20190611_QX3_LiSc_MA_Hela_500ng_LC15479.32478.8955.51.90.0-0.3-0.01.60.0478.826.70.626.726.527.10.0nannannannan163.046.05.00000.0231,655144.4106.813,166,700,000.0NaNNaN32461333;44NaN9606
AAAAAAGAASGLPGPVAQGLK21Acetyl (Protein N-term)_(Acetyl (Protein N-term))AAAAAAGAASGLPGPVAQGLK_NaNNaN100Q96P70Q96P70Q96P70IPO9Importin-9MULTI-MSMS20190611_QX3_LiSc_MA_Hela_500ng_LC15598.03597.71,790.02.40.0-0.7-0.01.80.0597.796.90.596.996.697.10.0nannannannan85.034.03.00000.01120,70646.636.8140,166,000.0NaNNaN441624455NaN9606
\n", - "
" - ], - "text/plain": [ - " Length \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 52 \n", - "AAAAAAAAAVSR 12 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 26 \n", - "AAAAAAALQAK 11 \n", - "AAAAAAGAASGLPGPVAQGLK 21 \n", - "\n", - " Modifications \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... Unmodified \n", - "AAAAAAAAAVSR Unmodified \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK Acetyl (Protein N-term) \n", - "AAAAAAALQAK Unmodified \n", - "AAAAAAGAASGLPGPVAQGLK Acetyl (Protein N-term) \n", - "\n", - " Modified sequence \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... _AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVG... \n", - "AAAAAAAAAVSR _AAAAAAAAAVSR_ \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK _(Acetyl (Protein N-term))AAAAAAAGDSDSWDADAFSV... \n", - "AAAAAAALQAK _AAAAAAALQAK_ \n", - "AAAAAAGAASGLPGPVAQGLK _(Acetyl (Protein N-term))AAAAAAGAASGLPGPVAQGLK_ \n", - "\n", - " Oxidation (M) Probabilities \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... NaN \n", - "AAAAAAAAAVSR NaN \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK NaN \n", - "AAAAAAALQAK NaN \n", - "AAAAAAGAASGLPGPVAQGLK NaN \n", - "\n", - " Oxidation (M) Score Diffs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... NaN \n", - "AAAAAAAAAVSR NaN \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK NaN \n", - "AAAAAAALQAK NaN \n", - "AAAAAAGAASGLPGPVAQGLK NaN \n", - "\n", - " Acetyl (Protein N-term) \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 1 \n", - "AAAAAAALQAK 0 \n", - "AAAAAAGAASGLPGPVAQGLK 1 \n", - "\n", - " Oxidation (M) \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 0 \n", - "AAAAAAALQAK 0 \n", - "AAAAAAGAASGLPGPVAQGLK 0 \n", - "\n", - " Missed cleavages \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 1 \n", - "AAAAAAALQAK 0 \n", - "AAAAAAGAASGLPGPVAQGLK 0 \n", - "\n", - " Proteins \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... R4GMQ1;O60341;O60341-2 \n", - "AAAAAAAAAVSR A0A0A6YYC7;Q96JP5-2;Q96JP5 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK O75822;O75822-3;O75822-2 \n", - "AAAAAAALQAK P36578;H3BM89;H3BU31 \n", - "AAAAAAGAASGLPGPVAQGLK Q96P70 \n", - "\n", - " Leading proteins \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... R4GMQ1 \n", - "AAAAAAAAAVSR A0A0A6YYC7 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK O75822 \n", - "AAAAAAALQAK P36578 \n", - "AAAAAAGAASGLPGPVAQGLK Q96P70 \n", - "\n", - " Leading razor protein \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... R4GMQ1 \n", - "AAAAAAAAAVSR A0A0A6YYC7 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK O75822 \n", - "AAAAAAALQAK P36578 \n", - "AAAAAAGAASGLPGPVAQGLK Q96P70 \n", - "\n", - " Gene names \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... KDM1A \n", - "AAAAAAAAAVSR ZFP91-CNTF;ZFP91 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK EIF3J \n", - "AAAAAAALQAK RPL4 \n", - "AAAAAAGAASGLPGPVAQGLK IPO9 \n", - "\n", - " Protein names \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... Lysine-specific histone demethylase 1A \n", - "AAAAAAAAAVSR E3 ubiquitin-protein ligase ZFP91 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK Eukaryotic translation initiation factor 3 sub... \n", - "AAAAAAALQAK 60S ribosomal protein L4 \n", - "AAAAAAGAASGLPGPVAQGLK Importin-9 \n", - "\n", - " Type \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... MULTI-MSMS \n", - "AAAAAAAAAVSR MULTI-MSMS \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK MULTI-MSMS \n", - "AAAAAAALQAK MULTI-MSMS \n", - "AAAAAAGAASGLPGPVAQGLK MULTI-MSMS \n", - "\n", - " Raw file \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 20190611_QX3_LiSc_MA_Hela_500ng_LC15 \n", - "AAAAAAAAAVSR 20190611_QX3_LiSc_MA_Hela_500ng_LC15 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 20190611_QX3_LiSc_MA_Hela_500ng_LC15 \n", - "AAAAAAALQAK 20190611_QX3_LiSc_MA_Hela_500ng_LC15 \n", - "AAAAAAGAASGLPGPVAQGLK 20190611_QX3_LiSc_MA_Hela_500ng_LC15 \n", - "\n", - " MS/MS m/z Charge m/z \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 1,101.8 4 1,101.3 \n", - "AAAAAAAAAVSR 500.8 2 500.8 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 879.4 3 879.1 \n", - "AAAAAAALQAK 479.3 2 478.8 \n", - "AAAAAAGAASGLPGPVAQGLK 598.0 3 597.7 \n", - "\n", - " Mass \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 4,401.1 \n", - "AAAAAAAAAVSR 999.5 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2,634.2 \n", - "AAAAAAALQAK 955.5 \n", - "AAAAAAGAASGLPGPVAQGLK 1,790.0 \n", - "\n", - " Uncalibrated - Calibrated m/z [ppm] \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 2.4 \n", - "AAAAAAAAAVSR 1.4 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2.2 \n", - "AAAAAAALQAK 1.9 \n", - "AAAAAAGAASGLPGPVAQGLK 2.4 \n", - "\n", - " Uncalibrated - Calibrated m/z [Da] \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0.0 \n", - "AAAAAAAAAVSR 0.0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 0.0 \n", - "AAAAAAALQAK 0.0 \n", - "AAAAAAGAASGLPGPVAQGLK 0.0 \n", - "\n", - " Mass error [ppm] \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0.2 \n", - "AAAAAAAAAVSR 0.5 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK -0.8 \n", - "AAAAAAALQAK -0.3 \n", - "AAAAAAGAASGLPGPVAQGLK -0.7 \n", - "\n", - " Mass error [Da] \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0.0 \n", - "AAAAAAAAAVSR 0.0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK -0.0 \n", - "AAAAAAALQAK -0.0 \n", - "AAAAAAGAASGLPGPVAQGLK -0.0 \n", - "\n", - " Uncalibrated mass error [ppm] \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 2.6 \n", - "AAAAAAAAAVSR 2.0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 1.4 \n", - "AAAAAAALQAK 1.6 \n", - "AAAAAAGAASGLPGPVAQGLK 1.8 \n", - "\n", - " Uncalibrated mass error [Da] \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0.0 \n", - "AAAAAAAAAVSR 0.0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 0.0 \n", - "AAAAAAALQAK 0.0 \n", - "AAAAAAGAASGLPGPVAQGLK 0.0 \n", - "\n", - " Max intensity m/z 0 \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 1,101.8 \n", - "AAAAAAAAAVSR 500.8 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 879.4 \n", - "AAAAAAALQAK 478.8 \n", - "AAAAAAGAASGLPGPVAQGLK 597.7 \n", - "\n", - " Retention time \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 85.6 \n", - "AAAAAAAAAVSR 25.6 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 95.0 \n", - "AAAAAAALQAK 26.7 \n", - "AAAAAAGAASGLPGPVAQGLK 96.9 \n", - "\n", - " Retention length \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0.3 \n", - "AAAAAAAAAVSR 0.2 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 0.6 \n", - "AAAAAAALQAK 0.6 \n", - "AAAAAAGAASGLPGPVAQGLK 0.5 \n", - "\n", - " Calibrated retention time \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 85.6 \n", - "AAAAAAAAAVSR 25.6 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 95.0 \n", - "AAAAAAALQAK 26.7 \n", - "AAAAAAGAASGLPGPVAQGLK 96.9 \n", - "\n", - " Calibrated retention time start \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 85.5 \n", - "AAAAAAAAAVSR 25.4 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 94.7 \n", - "AAAAAAALQAK 26.5 \n", - "AAAAAAGAASGLPGPVAQGLK 96.6 \n", - "\n", - " Calibrated retention time finish \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 85.8 \n", - "AAAAAAAAAVSR 25.6 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 95.3 \n", - "AAAAAAALQAK 27.1 \n", - "AAAAAAGAASGLPGPVAQGLK 97.1 \n", - "\n", - " Retention time calibration \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0.0 \n", - "AAAAAAAAAVSR 0.0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 0.0 \n", - "AAAAAAALQAK 0.0 \n", - "AAAAAAGAASGLPGPVAQGLK 0.0 \n", - "\n", - " Match time difference \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... nan \n", - "AAAAAAAAAVSR nan \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK nan \n", - "AAAAAAALQAK nan \n", - "AAAAAAGAASGLPGPVAQGLK nan \n", - "\n", - " Match m/z difference \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... nan \n", - "AAAAAAAAAVSR nan \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK nan \n", - "AAAAAAALQAK nan \n", - "AAAAAAGAASGLPGPVAQGLK nan \n", - "\n", - " Match q-value \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... nan \n", - "AAAAAAAAAVSR nan \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK nan \n", - "AAAAAAALQAK nan \n", - "AAAAAAGAASGLPGPVAQGLK nan \n", - "\n", - " Match score \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... nan \n", - "AAAAAAAAAVSR nan \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK nan \n", - "AAAAAAALQAK nan \n", - "AAAAAAGAASGLPGPVAQGLK nan \n", - "\n", - " Number of data points \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 84.0 \n", - "AAAAAAAAAVSR 37.0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 157.0 \n", - "AAAAAAALQAK 163.0 \n", - "AAAAAAGAASGLPGPVAQGLK 85.0 \n", - "\n", - " Number of scans \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 22.0 \n", - "AAAAAAAAAVSR 16.0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 47.0 \n", - "AAAAAAALQAK 46.0 \n", - "AAAAAAGAASGLPGPVAQGLK 34.0 \n", - "\n", - " Number of isotopic peaks \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 5.0 \n", - "AAAAAAAAAVSR 3.0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 5.0 \n", - "AAAAAAALQAK 5.0 \n", - "AAAAAAGAASGLPGPVAQGLK 3.0 \n", - "\n", - " PIF \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 0 \n", - "AAAAAAALQAK 0 \n", - "AAAAAAGAASGLPGPVAQGLK 0 \n", - "\n", - " Fraction of total spectrum \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 0 \n", - "AAAAAAALQAK 0 \n", - "AAAAAAGAASGLPGPVAQGLK 0 \n", - "\n", - " Base peak fraction PEP \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 0.0 \n", - "AAAAAAAAAVSR 0 0.0 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 0 0.0 \n", - "AAAAAAALQAK 0 0.0 \n", - "AAAAAAGAASGLPGPVAQGLK 0 0.0 \n", - "\n", - " MS/MS count \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 1 \n", - "AAAAAAAAAVSR 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 1 \n", - "AAAAAAALQAK 2 \n", - "AAAAAAGAASGLPGPVAQGLK 1 \n", - "\n", - " MS/MS scan number Score \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 106,834 102.7 \n", - "AAAAAAAAAVSR 30,184 68.6 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 118,493 157.9 \n", - "AAAAAAALQAK 31,655 144.4 \n", - "AAAAAAGAASGLPGPVAQGLK 120,706 46.6 \n", - "\n", - " Delta score \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 91.3 \n", - "AAAAAAAAAVSR 46.9 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 144.3 \n", - "AAAAAAALQAK 106.8 \n", - "AAAAAAGAASGLPGPVAQGLK 36.8 \n", - "\n", - " Combinatorics \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 1 \n", - "AAAAAAAAAVSR 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 1 \n", - "AAAAAAALQAK 1 \n", - "AAAAAAGAASGLPGPVAQGLK 1 \n", - "\n", - " Intensity Reverse \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 57,739,000.0 NaN \n", - "AAAAAAAAAVSR 87,575,000.0 NaN \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 442,780,000.0 NaN \n", - "AAAAAAALQAK 3,166,700,000.0 NaN \n", - "AAAAAAGAASGLPGPVAQGLK 40,166,000.0 NaN \n", - "\n", - " Potential contaminant id \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... NaN 0 \n", - "AAAAAAAAAVSR NaN 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK NaN 2 \n", - "AAAAAAALQAK NaN 3 \n", - "AAAAAAGAASGLPGPVAQGLK NaN 4 \n", - "\n", - " Protein group IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 1774 \n", - "AAAAAAAAAVSR 231 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 1877 \n", - "AAAAAAALQAK 2461 \n", - "AAAAAAGAASGLPGPVAQGLK 4162 \n", - "\n", - " Peptide ID \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2 \n", - "AAAAAAALQAK 3 \n", - "AAAAAAGAASGLPGPVAQGLK 4 \n", - "\n", - " Mod. peptide ID MS/MS IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 0 \n", - "AAAAAAAAAVSR 1 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2 2 \n", - "AAAAAAALQAK 3 3;4 \n", - "AAAAAAGAASGLPGPVAQGLK 4 5 \n", - "\n", - " Best MS/MS \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 0 \n", - "AAAAAAAAAVSR 1 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2 \n", - "AAAAAAALQAK 4 \n", - "AAAAAAGAASGLPGPVAQGLK 5 \n", - "\n", - " Oxidation (M) site IDs \\\n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... NaN \n", - "AAAAAAAAAVSR NaN \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK NaN \n", - "AAAAAAALQAK NaN \n", - "AAAAAAGAASGLPGPVAQGLK NaN \n", - "\n", - " Taxonomy IDs \n", - "Sequence \n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPG... 9606 \n", - "AAAAAAAAAVSR 9606 \n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 9606 \n", - "AAAAAAALQAK 9606 \n", - "AAAAAAGAASGLPGPVAQGLK 9606 " - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "pd.options.display.max_columns = len(mq_output.evidence.columns)\n", - "mq_output.evidence.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Sequence\n", - "AAAAAAAAAAAATGTEAGPGTAGGSENGSEVAAQPAGLSGPAEVGPGAVGER 0\n", - "AAAAAAAAAVSR 1\n", - "AAAAAAAGDSDSWDADAFSVEDPVRK 2\n", - "AAAAAAALQAK 3\n", - "AAAAAAGAASGLPGPVAQGLK 4\n", - " ... \n", - "YYVLNALK 38,785\n", - "YYVTIIDAPGHR 38,786\n", - "YYVTIIDAPGHR 38,786\n", - "YYVTIIDAPGHR 38,786\n", - "YYYIPQYK 38,787\n", - "Name: Peptide ID, Length: 49216, dtype: int64" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mixed_dtype_columns = mq_output.evidence.columns[[50, 53, 58]]\n", - "mq_output.evidence[mixed_dtype_columns][mixed_dtype_columns[1]]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13 (default, Mar 28 2022, 06:59:08) [MSC v.1916 64 bit (AMD64)]" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/misc_clustering_proteins.ipynb b/project/misc_clustering_proteins.ipynb deleted file mode 100644 index b7892c718..000000000 --- a/project/misc_clustering_proteins.ipynb +++ /dev/null @@ -1,1465 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "# Data views" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "#PCA-fct Annelaura\n", - "from sklearn.decomposition import PCA\n", - "def runPCA(data, components = 2):\n", - " result = {}\n", - " X = data.copy()\n", - " pca = PCA(n_components=components)\n", - " pca.fit(X)\n", - " X = pca.transform(X)\n", - " var_exp = pca.explained_variance_ratio_\n", - " args = {\"x_title\":\"PC1\"+\" ({0:.2f})\".format(var_exp[0]),\"y_title\":\"PC2\"+\" ({0:.2f})\".format(var_exp[1])}\n", - " if components == 2:\n", - " resultDf = pd.DataFrame(X, columns = [\"x\",\"y\"])\n", - " if components > 2:\n", - " args.update({\"z_title\":\"PC3\"+str(var_exp[2])})\n", - " resultDf = pd.DataFrame(X)\n", - " cols = []\n", - " if len(components)>3:\n", - " cols = resultDf.columns[4:]\n", - " resultDf.columns = [\"x\", \"y\", \"z\"] + cols\n", - " result['pca'] = resultDf\n", - " return resultDf, args" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Load Data \n", - "\n", - "Meta Data" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "Collapsed": "false" - }, - "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", - "
indexDateMS_instrumentLCPIDColumnLengthshortdate
SampleID
40820180713_QE8_nLC5_ASD_QC_Hela1_proteinGroups.txt20180713QE8nLC5ASDNaN201807
31220180713_QE8_nLC5_ASD_QC_Hela2_proteinGroups.txt20180713QE8nLC5ASDNaN201807
28120180713_QE8_nLC5_ASD_QC_Hela2_20190226172112_...20180713QE8nLC5ASDNaN201807
8220190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_02_pro...20190103QE8nLC0LiNi15.0201901
16120190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_01_pro...20190103QE8nLC0LiNi15.0201901
\n", - "
" - ], - "text/plain": [ - " index Date \\\n", - "SampleID \n", - "408 20180713_QE8_nLC5_ASD_QC_Hela1_proteinGroups.txt 20180713 \n", - "312 20180713_QE8_nLC5_ASD_QC_Hela2_proteinGroups.txt 20180713 \n", - "281 20180713_QE8_nLC5_ASD_QC_Hela2_20190226172112_... 20180713 \n", - "82 20190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_02_pro... 20190103 \n", - "161 20190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_01_pro... 20190103 \n", - "\n", - " MS_instrument LC PID ColumnLength shortdate \n", - "SampleID \n", - "408 QE8 nLC5 ASD NaN 201807 \n", - "312 QE8 nLC5 ASD NaN 201807 \n", - "281 QE8 nLC5 ASD NaN 201807 \n", - "82 QE8 nLC0 LiNi 15.0 201901 \n", - "161 QE8 nLC0 LiNi 15.0 201901 " - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import os\n", - "import ipywidgets as w\n", - "import pandas as pd\n", - "from config import PROCESSED_DATA, PREFIX_META\n", - "meta_data = pd.read_pickle(os.path.join(PROCESSED_DATA, PREFIX_META + '.pkl' ))\n", - "meta_data.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "Select imputed protein data for protein groups present in at least the available percentage of the samples" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "46aeae4fd95846ea808833aff7f2d318", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Dropdown(options=('hela_imputed_proteins_50.pkl', 'hela_imputed_proteins_90.pkl'), value='hela_imputed_protein…" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "w_data = w.Dropdown(options= [x for x in os.listdir(os.path.join(PROCESSED_DATA)) if '.pkl' in x and not 'meta' in x])\n", - "w_data" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## PCA \n", - "- How good is the reconstruction using the first two principal components?\n", - " - it works relatively good on MNIST, also here?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Explained Variance\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "data = pd.read_pickle(os.path.join(PROCESSED_DATA, w_data.value))" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "from sklearn.decomposition import PCA\n", - "pca = PCA()\n", - "pca = pca.fit(data)\n", - "CDF_var_explained = np.cumsum(pca.explained_variance_ratio_)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "import seaborn\n", - "import matplotlib as plt\n", - "g = seaborn.relplot(data=pd.Series(CDF_var_explained))\n", - "g.set_axis_labels(\"Principal Components\", \"cumulative share of explained variance\")\n", - "_ = g.fig.suptitle('Explained Variance by Principal Components', y=1.03)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "90 percent of Variance is explained by first 163 principal components\n" - ] - } - ], - "source": [ - "print(\"90 percent of Variance is explained by first {} principal components\".format(\n", - " np.argmax(CDF_var_explained >= 0.9)\n", - "))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### First two Principal Components" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "n_components = 2\n", - "from sklearn.decomposition import PCA\n", - "pca = PCA(n_components=n_components)\n", - "data_2PC = pca.fit_transform(data)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Variance share of PC1: 0.414, PC2: 0.130\n" - ] - } - ], - "source": [ - "print(\"Variance share of PC1: {:.3f}, PC2: {:.3f}\".format(*pca.explained_variance_ratio_))" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "Collapsed": "false" - }, - "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", - "
PC1PC2
SampleID
408-12.037074-27.105675
281-13.252902-31.794649
8234.371093-3.456893
16142.6033772.525639
25126.988896-5.811818
\n", - "
" - ], - "text/plain": [ - " PC1 PC2\n", - "SampleID \n", - "408 -12.037074 -27.105675\n", - "281 -13.252902 -31.794649\n", - "82 34.371093 -3.456893\n", - "161 42.603377 2.525639\n", - "251 26.988896 -5.811818" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data_2PC = pd.DataFrame(data_2PC, index=data.index, columns=[f'PC{i}' for i in range(1,n_components+1)])\n", - "data_2PC.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Plot Principal Components\n", - "- there must have been a change in HeLa batch in june 2019 \n", - "- there are also a few runs from before/after that month that falls in the wrong cluster" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "# PCA\n", - "# Original data\n", - "result, args = runPCA(data)\n", - "result.set_index(data.index, inplace = True)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "result = meta_data.join(result)\n", - "result['shortdate'] = result.shortdate.astype('category', copy=True)\n", - "\n", - "seaborn.relplot(x='x', y='y', hue='shortdate', data=result )" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Other Plots (work in progress)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/tzx804/env/fixjupyter/lib/python3.7/site-packages/ipykernel_launcher.py:4: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", - " after removing the cwd from sys.path.\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAy4AAAIhCAYAAACoku7KAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdd3hUVf4/8PedPsmk9wIkQEgPCaFKDc1QBAQEERVsa10Uv+p+f667gh2/67pFV3dRF9RFFCsKgmAAlU4goUMSSEggJKSXSTLl3t8fyKwxmRSSzNwk79fz+Dxyzr3nfoYjkffcc88VJEmSQEREREREJGMKZxdARERERETUGgYXIiIiIiKSPQYXIiIiIiKSPQYXIiIiIiKSPQYXIiIiIiKSPQYXIiIiIiKSPQYXIiIiIiKSPQYXIqJWhIWFQaPRoKSkpFF7UlISBEFAbm4uli5dimeeecbW9+677yIqKgpubm4ICAjA9OnTUV1dDQAoKCjAvHnz4OvrCw8PD8TFxWHNmjUAgNzcXAiCAIvFAgBYunQpBEHAgQMHbGNnZ2dDEIRGtWzbtg0pKSlwc3ODj48PEhMTsWrVKtTX1wMAVqxYAUEQ8Mknn9jOsVgstvqvXUuj0cBgMNj+GTx4cIc/ExERUWdgcCEiaoPw8HB89NFHtl8fO3YMRqOx2WN37dqFp59+Gh999BGqq6tx6tQpLFy40NZ/xx13oE+fPsjLy0NpaSk++OADBAQE2L22t7d3o1D0axs2bMD8+fNx22232cb8+OOPUVBQgPz8/EbjPPvss7BarXbHeuqpp1BTU2P7JzMzs0s+ExERUXsxuBARtcEdd9yB999/3/brtWvX4s4772z22IMHD2LUqFFISkoCcDUwLFmyBG5ubrb+pUuXwtXVFSqVCklJSZg2bZrday9ZsgRHjx7Frl27mvRJkoTHH38cf/zjH3HffffB29sbABAZGYm///3viIiIsB2bmpoKjUaDDz/8sN2fv7M/ExERUXsxuBARtcHIkSNRVVWFU6dOwWq1Yv369bj99tubPXbEiBHYunUrnn32WezevRsNDQ1Nxnr44Yexfv16XLhwodVru7i44Omnn8bvf//7Jn1nzpyxLdNqjSAIeP7557Fy5UqYzeZWj/+lzv5MRERE7cXgQkTURtfuumzbtg3R0dEICQlp9rixY8fi888/x+HDhzFjxgz4+Pjg8ccfty3R2rBhA8aOHYvnn38e4eHhSExMxMGDB1u89v33348LFy7g22+/bdR+7bmbwMBAW9utt94KT09PuLi44IMPPmh0/KxZs+Dn54d33nmn2ev86U9/gqenp+2fJUuWdNlnIiIiag8GFyKiNrrjjjuwbt06rFmzxu4ysWumTZuGr7/+GmVlZfjqq6+wZs0aW1jw8vLCK6+8ghMnTqCoqAiJiYmYM2cOJEmyO55Wq8Uf/vAH/OEPf2jU7uPjAwAoLCy0ta1fvx4VFRUYMmRIs8+zvPDCC3jxxRdtD+7/0hNPPIGKigrbP2vXru2yz0RERNQeDC5ERG3Ur18/hIeHY/PmzZg7d26bzlEoFJg0aRImTpyI48ePN+n39fXFE088gUuXLqGsrKzFse666y5UVFTg888/t7VFRkYiJCSkUVtrpkyZgoEDB+If//hHm8/5pc78TERERG3F4EJE1A7vvvsu0tLS4OrqaveYr776CuvXr0d5eTkkScKBAwewa9cujBw5EgDwu9/9DsePH4fFYkF1dTXeeustDBw40Hb3xB6VSoWVK1di1apVtjaFQoHXXnsNK1euxOrVq23XzMrKQlFRkd2xXnzxRbz66qtt/txd9ZmIiIjaisGFiKgdBgwYgKFDh7Z4jJeXF1avXo2IiAi4u7vj9ttvx5NPPonFixcDAIxGI26++WZ4enqif//+yMvLw8aNG9t0/UWLFiEoKKhR28KFC/HJJ5/gww8/RJ8+feDr64sFCxbgN7/5DW655ZZmxxk9ejSGDx/epP3VV19t9B4XX1/fLv9MREREbSFIXIBMREREREQyxzsuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuREREREQkewwuXai+vt7ZJdCvcE7kh3MiP5wT+eGcyA/nhMjxGFy6kCiKzi6BfoVzIj+cE/nhnMgP50R+OCdEjsfgQkREREREssfgQkREREREssfgQkREREREssfgQkREREREssfgQkREREREssfgQkREREREssfgQkREREREssfgQkREREREssfgQkREREREssfgQkREREREssfgQkREREREssfgQkREREREssfgQkREREREsqdydgFERL8kWa3A6T2QyosgeAcBUaMgKPgdCxERUW/H4EJEsiFlHYK47jmgsuTqrwHA0x+K21dC6D/YqbURERGRc/FrTCKSBelKPsR3n7SFFpuKYoirH4dUftk5hREREZEsMLgQkSxIP30KmBqa72yog7T7c8cWRERERLLC4EJE8pBzuOX+7HTH1EFERESyxOBCRPKgVHesn4iIiHo0Bhcikof4cS33J0xwSBlEREQkTwwuRCQLwqibAe/A5jt9QyAMn+nYgoiIiEhWGFyISBYEVw8oHnoTQuwY4Np7WxQKCPHjr7brDc4tkIiIiJyK73EhItkQvIMg3PMqpKoSoOIK4BUAwc3b2WURERGRDDC4EJHsCO6+gLuvs8sgIiIiGeFSMSIiIiIikj0GFyIiIiIikj0GFyIiIiIikj0GFyIiIiIikr1e+3D+sWPHsGvXLlRWVsJgMGDOnDno16+fs8siIiIiIqJm9MrgkpOTg+3bt2P+/PkICQlBTU2Ns0siIiIiIqIW9MrgsmPHDowfPx59+vQBALi7uzu5IiIiIiIiakmvCy6iKOLSpUuIjIzEX//6V1gsFkRFRWHq1KlQq9WoqqpqcgfGYDBcV7gRBKGzyqZOwjmRH86J/HBO5IdzIj+cEyLH63XBpaamBqIo4uTJk7j77ruhUCiwfv16/PDDD5g0aRLS09Oxa9euRueMHz8eKSkp7b6WXq/vrLKpk3BO5IdzIj+cE/nhnMgP54TI8XpdcFGr1QCAESNGwM3NDQAwatQoW3BJTk5GZGRko3MMBsN1Xauuro4/2GSGcyI/nBP54ZzID+dEfjgnRI7X64KLXq9vcdmX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vPrqq8ybNw+A//znP8q4a9asITk5WflId3Fx4cCBA8TGxrJu3TpFmzFp0iTWrl3L4sWLWbt2reKLc8899/Doo49iMpkwGo0cPHiQxx9/nMLCQrRaLa6urtTW1rJz506efvppJEli5MiRfP7558ycOdNqLFvztcWECRO4ePGicuzk5ERmZiYA/v7+7N69m7lz55KWlkZdXR2enp6UlZUxYcIEXnvtNW6//fIGl6+vL6mpqRQWFuLp6cnOnTsJCQnp6DJacUsLLmazmS+++IKoqChFcImJiaF///5W7VqGgOsMtbW1XeLBJssyp86kcuyn45RVluPs6ERkUASRgRGoVF3f5MrxOuaF6CprIriMWJOuR1dck9kREbz0/XfUNDRYlUuSxJyIyGv2O8mvbh1swNwiqqGxhflDMyV1tY11ZjNvHz/B/rz8y5VpMLSHN09EDUDfjhlGZ+mKa3KrI9akbWw5zv8SzJo1i8TERIqKijAYDLzwwgvMnz+/zbbJycm89957rFq1Cnd3d5599lkGDx4MwHPPPac46r/++us88MADPPbYY3h6evLhhx8CjWGK//d//xdJkoiPj++Qz8a7777L3Llzqa2tZdy4cYwbNw6AxYsXM2PGDFavXk2vXr349NNPAQgJCSEhIYHIyEhUKhULFiwgPDyc48ePM2fOHMxmMxaLhRkzZiihjF9//XVmzpzJ3/72NwYOHKhcf3vzHTZsGKdPn6aqqgqDwcDq1asZO3aszev4xz/+wUMPPcTSpUuRJIk1a9YgSRLLly8nMzOTF198UTHP27FjBz4+Pjz//PPEx8ej1Wrp1asXa9asuer9agtJbi/u7G8Yi8XCF198QX19PbNmzWrXzu9aqampwcHhl0vG1hayLLN1/zZOnkltVdfPrw9T7rznphBerhddYU0E1og16Xp01TXJq6pkS0YGh/LzMFks9HNzo4eDPTqVGg97e+7w74WrXec+JBd/t5+MJgfcZkrr6hRTMWetlh4O1mManJ35/0bcybsnTrLtQttBA0b6+vB4lG1n4M7SVdfkVkasiUDwy3PrfLG2QJZltmzZQnV1Nffdd98NEVq6CmdyzrYptABkZp/llI06gUAg6Gr4ODnzx4HRrB4/kT8NjOZccRH7zmex69wZPkk9ycLtW9lz7mynxrzTr3Veh5b+Mi661uHZR/cKoMJoZE9T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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# look at missing values\n", - "miss = x_50.T.isnull().sum().astype(float).tolist()\n", - "df = result_to_plot.loc[result_to_plot['variable']=='shortdate']\n", - "df['missingness']=[(mis/x_50.shape[1])*100 for mis in miss]\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y', color='missingness'),data = df)+geom_point(size =75, alpha = 0.8) + scale_color_gradient(low = \"#00AFBB\", high = \"#FC4E07\")+theme_bw()+ggtitle('MISSINGNESS')" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "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ERFJQ0WziIiIiEgaKppFRERERNJQ0SwiIiIikoaKZhERERGRNFQ0i4iIiIikoaJZRERERCQNFc0iIiIiImmoaBYRERERSUNFs4iIiIhIGiqaRURERETSUNEsInKVampq+M53vkNdXR2FhYU89NBDRKNRuru7ufvuuwkEAhQXF3P33Xdz6tSpwXYrV67km9/8JjfeeCMFBQXcdtttdHR0ABCNRvnsZz/LhAkTKCoqYtGiRbS2tmbqKYqIjHsqmkVEhsHPf/5zXnjhBY4dO8aePXv44Q9/iGmafP7zn6epqYkTJ07g9Xr56le/OqTdz372M5588kna2tqIx+N85zvfAeBHP/oRvb29nDx5ks7OTn7wgx/g9Xoz8dRERAQVzSIiw+LP/uzPqKqqoqSkhHvuuYeGhgYmTJjAgw8+iM/no6CggMcee4wtW7YMaff5z3+emTNn4vV6+dSnPkVDQwMATqeTzs5Ojhw5gt1uZ+HChfj9/kw8NRERQUWziMiwqKioGPzd5/PR399POBzmT/7kT5gyZQp+v5/ly5fT09NDKpW6ZDuA9evXc/vtt/Pwww9TVVXFX//1X5NIJEbvCYmIyBAqmkVERsg//uM/cvDgQbZv304wGOT1118HwLKstG2dTid/93d/x759+9i6dSvPP/88P/7xj0c6ZBER+QgqmkVERkhfXx9er5eioiK6urr4+7//+8tu++qrr/L++++TSqXw+/04nU5sNr1li4hkit6BRURGyF/8xV8QiUQoLS1lyZIl3HHHHZfdtqWlhU984hP4/X5mz57NihUrWL9+/QhGKyIil2JYl3OcUERERERkHFNPs4iIiIhIGiqaRURERETSUNEsIiIiIpKGimYRERERkTRUNIuIiIiIpKGiWUREREQkDRXNIiIiIiJpqGgWEREREUlDRbOIiIiISBr/Pxn8j2yoG9RnAAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Make 'before' and 'after' datasets\n", - "labels['datetime'] = pd.to_datetime(labels.Date, format = '%Y%m%d')\n", - "labels['time'] = 'after'\n", - "labels.loc[labels['datetime']<'2019-06-01','time']='before'\n", - "# check number of nans\n", - "nonan = x.isnull().sum(axis = 1)\n", - "nonnan = pd.DataFrame(nonan)\n", - "nonnan.columns = ['nans']\n", - "nonnan['time']=labels['time']\n", - "#from ggplot import *\n", - "ggplot(aes(x='nans', color = 'time'), data = nonnan) + geom_density() #+ ylim(0,0.025)\n", - "\n", - "## There are fewer identified proteins (more missingness) in the \"old\" HeLa" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(177, 25427)\n", - "(175, 2069)\n", - "(296, 25427)\n", - "(223, 2375)\n", - "overlapping: 1451\n" - ] - } - ], - "source": [ - "# datasets with 50% coverage for both 'before' and 'after' \n", - "\n", - "x_50_before = coverage(x.loc[labels['datetime']<'2019-06-01',:], 0.5,0.5)\n", - "print(x.loc[labels['datetime']<'2019-05-01',:].shape)\n", - "print(x_50_before.shape)\n", - "x_50_after = coverage(x.loc[labels['datetime']>='2019-06-01',:], 0.5,0.5)\n", - "print(x.loc[labels['datetime']>='2019-05-01',:].shape)\n", - "print(x_50_after.shape)\n", - "\n", - "# Overlapping proteins\n", - "print('overlapping:',len(list(set(x_50_before.columns.tolist()) & set(x_50_after.columns.tolist()))))" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/tzx804/env/fixjupyter/lib/python3.7/site-packages/ipykernel_launcher.py:4: RuntimeWarning: divide by zero encountered in log\n", - " after removing the cwd from sys.path.\n" - ] - }, - { - "data": { - "image/png": "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SAaDwezau3btkoKCgko/DgoKklxcXCR3d/fSXy+++GLp13FycpLc3d0lNzc3qUGDBtKQIUOkM2fOVJg9KSlJUqlUpY+pW7euFBsbK6WkpJSeExwcLM2dO9fssTNmzJBatWpV5tjfv4cpKSmSTqeTbt26Zfb4pk2bSvPmzaswGxGRtakkqZwd2omIiIiI7BSXKBARERGRorDgEhEREZGisOASERERkaKw4BIRERGRorDgEhEREZGisOASERERkaKw4BIRERGRorDgEhEREZGisOASERERkaKw4BIRERGRorDgEhEREZGisOASERERkaKw4BIRERGRorDgEhEREZGisOASERERkaKw4BIRERGRorDgEhEREZGisOASERERkaKw4BIRERGRorDgEhEREZGisOASERERkaKw4BIRERGRorDgEhEREZGisOASERERkaKw4BIRERGRorDgEhEREZGisOASERERkaKw4BIRERGRorDgEhEREZGisOASERERkaKw4BIRERGRorDgEhEREZGisOASERERkaKw4BIRERGRorDgEhEREZGisOASERERkaJoqnJSQUEBEhMTcfnyZbi5uSE6OhqhoaFm5xmNRmzbtg3nzp1DSUkJGjRogB49esDT09PiwYmIiIiIylOlV3C3bt0KtVqN+Ph49OrVC1u2bMGtW7fMzjt48CCuXr2K0aNH47XXXoOLiwu2bt1q8dBERERERBWptODq9XqcOXMGUVFR0Ol0CAoKQnBwMFJTU83Ozc3NxT/+8Q94eHjA2dkZzZs3R2ZmplWCExERERGVp9IlCllZWXBycoKfn1/psTp16iAtLc3s3Mcffxzbt29HXl4eXFxccPLkSTRp0qT083l5ecjPzy/zGL1eD3d395o8Bzg7O8NgMNToGnLTaDTw9vZGTk4OjEaj6DjVwnnLi/OWF+ctL85bXpy3vOxx3rVr1xYdwSIqLbh6vR46na7MMRcXFxQXF5ud6+vrC09PT3z66adQqVSoU6cOunfvXvr5Y8eOYc+ePWUeExkZiaioqAfNb/e8vb1FR3AonLe8OG95cd7y4rzlxXlTdVRacLVarVmZLS4uNiu9ALBlyxaUlJTg9ddfh1arxf79+7FmzRqMGDECANCqVSsEBweXeYxer6/xMgadTldu4bZl9vw3Us5bXpy3vDhveXHe8uK85WWP83aY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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# look at the distributions\n", - "from ggplot import *\n", - "ggplot(aes(x = 'A0A075B6E2'), data = x_50_before)+geom_density()+ggtitle('RAW DATA')\n", - "x_50_before_log = pd.DataFrame(np.log(x_50_before), columns = x_50_before.columns)\n", - "from ggplot import *\n", - "ggplot(aes(x = 'A0A075B6E2'), data = x_50_before_log)+geom_density()+ggtitle('LOG TRANSFORMED DATA')" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAWYAAAEMCAYAAAD3SRwqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOy9eZRkRZ33/Ym49+ZaWVWZlbVk9krT9EbTO90NvSYoigvKgAw+DC4objg8qC+PDIM6KMcD40EdnsEZxVHU4cFBGRD3BbKq951eoZfqvSuzlqzMqso97xLvHzepppinoR3g1fNa33Py1I2KyBtx40b84renUEoxjnGMYxzj+POB/FMPYBzjGMc4xjEW44R5HOMYxzj+zDBOmMcxjnGM488M44R5HOMYxzj+zDBOmMcxjnGM488M44R5HOMYxzj+zPCmEWYhxNuFEIeEEN1CiLverH7GMY5xjONPCSHE94QQ/UKI/eeoF0KIh+q0cK8QYtFr3fNNIcxCCA14GLgamAO8Xwgx583oaxzjGMc4/sR4FHj7q9RfDVxU/3wM+JfXuuGbxTEvBbqVUseUUjXgx8B73qS+xjGOcYzjTwal1Dog+ypN3gP8ULnYAjQLIWKvds83izBPAE6/rHym/r9xjGMc4/hLwx9ND/U3dTivAiHEx3DZeh6YNmPxtNISFoQzPFhqYkXNgwDefXUf//67dq6fcRqjWdD68yP8IrwKB1h7TwRtzXs4fePXsR3J7UV4tm8vvw6v5Pu+GncqB8uW7CfIBVYVn2YzeWoOpQSPpeIYCqbUHK5Yk2ZXZyutgTILe3bxi/AqTCHY7ZVMN+HmTCc/iq5lQTDHJSf3cGT2HLp7IzzkLdIgdP5H1c8WnyCDyb+lNvH8hEU8X2viloEkB6fPpVz2cLQc4tILeikOeXghF+FCf55TpQbOGBoVCSucAifsILpSjGiSKyam+GJfhK+vyLL32RZaQ0WiU4tURzS+2dfOxaYGwG7D4guz03Q82z06r3snLeBJqxkDwVqzRK/joyAlH8ok+V5rggEN+qRNFUWH0nmrXUAKxUZC/IJB2qSfiwlwlZNnCyEWWGXu1Us8/fCV7PnEJtpb8/z7UBtVofho8wDlokFqJMTitf0Y06M4g3lG9tQwy+4YT/U2s+Ddw3z/t20sqlVY+GFF788KHBsMEw8WmPbJNuzjaX7/n2EmaWVaIkValjiYvSYdz3aTjFzGrEsGEBJ+s28Si4NZflmN0GLDO2ed5rEjkwjbsEAf4YIrSnz0uSAzRJDr7CLPiRDXNg5QLHjIlP1cPLufWlEjn/WxtRLm5/oI/zJtmL873soi2wfAtRNT7DjewTR/HtsR3KNs3m+FkSjedcMIe3/s5YJpgzx+ZgKf703y3thi5ogQf+MfJNhcQ/c6/OD4RO5OJ8lcO4PoU4f5XXgFAFflNrJ/6nwqVZ3p/8Ng8/d0JjQU+FzNYaLWwFLLyyf7k9wUX84S288vGOSR9hqPDnSQFiaPpDYC8N3WBD264m9a+rg94+ODtUaOeSQfnHmaypDOL3tjTK1ZHPHozKxZ+IXFiDJ4T24d+6fO5wtVg/eaIRYFsxzON9MuK0yemmPyjsPcGFvGGjvAj1SaH7ZKRoZ8/JRGrmcE25Fc2ruDh9oTJGWeBTTwc7OHHZkjPNSeYL5ZYaPXx7BwiNmSO/qS3BVfwy2hDPsGolzgy/M1ZTBZ+Hgg1QXAr8Mr8QmbfYaP2/uS3BNby9walKRgkXeIdWYzCV+WfzFDvK9is8Pj4zOn/l28XvpjZo6ddy4KT+uFH6dOq+r4jlLqO693DK+GN4tj7gEmvaw8sf6/USilvqOUWqKUWnL36QLrvTazuvezo9bLhzJJPphJUj5qYgO/f3ESgy96+VD8MiYGC+zx6Vh7u1FWlVS2kQNDYZ7t28s7OxZydW4DT6S3UbM0LhvYRq8Ov/Lr/NzjI5/1YZuCu9NJJLDdB+u7Otjh87CwZxcAu30612bXcW+6kx7dff/dBlxycg8Amwba+YNf8uve5/lJejvXZtfxQKqLf0ttAmBhzy5uGUgCMKt7Pwt7dnHAK9h9rJ05R/dxfbaLQ5VGqkJwW38SE/i91sCNg51cn+3iloEkm0/F+GFqM9GfHOKK7CYG8kFiXd1k+4J8M7WO75Hm1oEkD6fWjyHKAEMlH/emO7knnSRvG1yf7WKbx2RaU4xbBpJ8NJGmgsOvikf4QjrJ8v7t5Go+XtBqrJQRyljck05SNg1u70uyenALz/btBdtiZWYrxbyXM6JGuy3JD/u45OQetvh0jm9uRDkO1ZNlNp+I8bNsO5lMkILSiPzgAMNCkchuRng9NE2ocNzQ6S8GsI+nqRwpscmnqNkalZJB5bhF76EQP42s4bDuI9bVjV2DD2WSnBkJcVdvkoOGTXx9N3f2Jtlv2CxJ78TKmDyV3kEWi6V9O9gjSsw8vJ+dZhPL/y5MLhXgxVOt6B6bWweSPJPeSf+JRn6Y2kxFwB19SabsPMRer2Bhzy6WpHfym97dPCJ7edooEv7WLm62jjJ5x2F+avdwR3w1T6d3ksFkztF9TNl5iBOHI9ydTvLjlrX8fl0ccAnykHB5oEMjzew3G2l+cAtX5zYw7/RufELHj2TQPct4LLWFz/QlebZvL33pRo6LyihRnhOZzL+qM3wp3UluMMDnTS+HvZK7epPkzvi5YM9BdmgV4v4in+lLUhCSg7qPzX7Bx+Ir2FGIUFYWp+tr+rpsFyszW5m84zDRQCOGEPRoik0DBykXDXrLQfarPItSu7i0dwePtazFBp5K7+BL6c5Ronx7X5KU8HJ3OskDqS7u6EtyaesM5lcF/zHSxn6vYLfZxOPpraNEGeDq3AZMJbm9TsQPUMBQilsGknzdcYl1Jh/gW6kNJLKb2SVKr4MsvQyOfd6fl9Oq+uePJcqvSQ9fiTeLMG8HLhJCXCCE8AA3As+c75cf7Eics27BmefHlK/Ibhq9/mXv2LotbZeOKU94t2/0eoPIn+9wuDfdOXZ8qXXnbPvb8Mpz1m1rX3Lefb4SPZdfdN5t3xtbPHp9T2ztmLqWxw+e83uvfM5XYk3bxaPXn+lLjql7XAZGr28cHHuf3sT0MeWew02j107ZHFP3pNU8pjygnb2+Lb5qTN3B6XPHlNt/e/aQ+vUr3kPj//rF6PXeoRZeDVfWKuesOzXSf866V663pbG+MeV9U+aPXmfeN3NM3bdSG0avb4ovH1P3o9SWMeUdmSOj19/1jmUek5HLxpQDyhm9/k6duL+Ex1vWjl53zxlrm7+0dcaY8sbostHrPdrY+dmhnXu+fuopnrPulegyx87XMst3jpZvAJRz/p/Xj2eAD9S9M5YDw0qp9Kt94U0hzEopC/g08FvgReAJpdSBV/vOw6n1ADyfOcqAdLgrvgbvBMln+lzu2ROweDS1GQANiPzgAMIbBKDHcB/jhthSHm5zifqKzFZGTA9fSCdpdzQeSHXR/E/bmLb3IBc0dVBWFl9LdXHAq2HjiocA96TPEpweafHP7WcPiU/FV/LBTPJVD44GzSU061qWjy7msCN4T24duZqPG2PLuHGwky0+xcfiK6gKxRfqfU5pbAfg/YOd3Bhzv/u1jgSN3iqOJYi0F7kzvoZh2+Uaru5YOHYO2xIY0uHp9E5Wts0mIGy8CPpUlWPDZ9fBt1IbyFXPHkxvy22g1ylzRfslPJ3eCUBFaWPuTXOUrv4DNLeWqOAuVk26f9c5Wd5SVjQ/uGWUg59WsznkNHBNbj1ao6AoHLoil+FkhlmS3slt/UkUAn16HOmBi00NUwnuTXcyYdMRHEfgUw6TTDi9dAZCQgBJrb5k89joHocWf4hDjvssmWtdYhJB5w9+yQz8ABw0bL7XmmDuiT1EjApTtbPEQtdtAO7qPfveK4777LfFV6FLjYxZ4C12A4N/PQuAA9PmEZJeZlsavYnpmLhSsVKCnO0B3MNJ9zr8bXwV325L4FVqlEM1lEIGzmoRj9YyAGxUQ1zaOoO0fXZ8NXvsexisjrC23T2QlqR3UlE2R0WVa2NLaAhXSWQ3M0P5yJZdopbRdDosm0blzpsp4De9u7knnSTguO/vY/EVVEoGmdIIvXYJR4CBpHVakQNenWfSO/EaFgBDmsDH2DGl7SI3x5dTkIK3ts8b/f/p8gBPprcTtSFqC0YkxBsiXN46iyXRs4zGVbmN3Btby+aBg5SVxW98bl+tlsN1sUtp8Jij+2GieIOIteOc/+c1IIR4HNgMzBRCnBFCfEQI8QkhxCfqTX4FHAO6gUeAT73WPd80HbNS6lf1Ab0mTi6eyc/OxHnvpB4+ctpHUEmaHJA+jQc6EvzNtDMYTRafy6zmyrKiVHUY+cd3gaZzcPpc0ln3xH4ivY1rW9aypu1i/snjQYoiD3kSNFnwTHgVa+9sYPjpo0zadpgPBGZxbVuCj6eTPBVZzURPiRtiS/nrqh+J4lc+m6mOznum9BBwEqwIDzDz8Ab2TlpAZw0WRacT1YNc60R4Ubd4qH6wDNsePhtfzerUOo7Pn8Vu30IOlhU9l19Evn+Itw+1ctfEhZwsQr/uQQOen7CIhT27mB2I8VVjNok5Z7jrqLuR5lZN/GETb6uDmRMElOCF7CkebkvwWzFCz4rp/MNxl6D7TYiES/ytsYqo0ljT38mj0QRfyGzn4sgUPuCZxud7k9wRX01KVYgKD91Ongc0jaedRg6LMle2z2O1jNAmR3jYSHCBafG/vQUQ7ng0Q/FYaguXts6gMVpmS/VS+mp+Lrmol+Gr1uKkBsnvrWJWBrBqGrt9C9FbbS6wNfxGCRH0sW/KfLrzTcSCI4hgM97ZzbTvsGj2VXmkNcH11w1hnh7Bd9AkMxzF2+pgF2CqJYl58jzYkSBgQUN7jU/mFnORKbgrchnRpzZzVcd8LBTXmxW2yCDH589isL9ItxPi2LxZjGQtlBJ8rSPBnb1JmlrLXFe7lCfT27kvluCTV/RyqrPMFuNSdFXiYcfmet+FNJgK5Sg2RpfRHBvkr7on8fH+JNetmYl+SPD8hEU0tYwQzPl4yJPgXe1pglMdLj+h4VM2fmw+EL+Mz8oKuVIV4ffwVGQ1zZj83GcwO9ZOwmmgX2/itKjxxdhatqthOhrzfM63mkFMHk1tRhOSSVoDAEfnzuZfs36+lurirvgajOAQx+fPYtMZRVYY3BNbS7xSI6SbFMwA+6bMx7KGeXvHAm6ymrnAP8SNvmV8J7WRe5bMgBPglwYzaoL1UuJYkBAjfCR+OU1NQ5CG2/qTfCm2lksiU3mnbwoHnDxR6eNy08sSzzAnnQgfaVnLsCb4Z+s4N8fncWWon+2ZViaqKitD02kXXkrYrIzHmGtqLNBH+HfhsCg6nQ7p52Lbw13xNUy1i8SFH59nhGlmA78Nr+QF+43hJdUbwwnX76Xe/xr1Crjtj7nnn0XkXyHnZatWpjTk4fd9exHAt81j2CMm/dLGLEuUBVks3pFbz1GPdE8yq4bhswkaZ8XhghSYymbBmeexHUlVgAJsITj1nRSVvM7fxldxUlQpi5e+I7EdQc6p0KtLTARVHApCMWnbYYYljIz4uDW+gmLFQ04qdmW6mSUb+WR/kjw2K9tmA/CO3HpKdY6yXDC407QpSUF5yMB2JL06FCseylIypMFJXbGwZxcPtSf4oNnMAS9kTjQQQqdnxXTyQiNf8GKNQHHQQ5+w+HZbgqwGFWVhljQeSW3kkdRGpIJiwcM9l6QZFDYbostwBNzfkSBvlZlXdecppSoE6zrPv68FsGzJvelOjphZDpdSfCndyVDZS5+mKAuJQkHV5dIzPQ3cHF9OSHrJZ30ct4MM6por9ZUrhL+3j8k7DlMueKhVNdLFIPZwlX6pKJsGKl8mvrxKStewbIkazGGdHqEiJIMVPwKw+4qUezXmHN1Hk2NTGxTUChq39SeRUnFSWlQE1PKSPWqEHgNMJci8byZZq8SDqXWMWB7OaDanzzRjWhpXf1rDqmrkSr5RewKAbUr66xyqiaJywmST2YTlSPorAea1XEBJOJhCIH0ag7aHYsZLWcCj0QQTnjpGn6pQqelYVQ0hFRmpyA4EsbIO7x/sJKVr5IXOD1ObKVcNikoHKRiWmqs3tbPEhY+chC+nOxlRJr3CxFI2UnPopcZpu8i1sSUIIThoZvlw/HJGcn46zTT3dyQo4hDr6qZcMDhjCEpSEkCQ1jwcUkFymiCbD7CwZxeDdol+XTDv9G5sHL7XmqA05HL6L5Z7KWiwvv8FihkPqUoAE8XO/jbAleDuTXcihGAEm8PVfgJo9OlwqNJInzB5UKYYkmBInTw2Mw4dwBFQVZKysuhVFU47Rb6ZWkdBupy/gWBXppuj1jB56e7ZH2l+wkqjWPawX+WxEQxob1D++DeQY34z8GdBmF8P8kPnL9rMPbHnDekzLazzbvtl5/zH92tv9b8znP+Cl+taXwsPe+03pM8/Bse6Gs67bUG+MUv0uf9tvnajOhap89eLHp4/7b8znP+CvdarucGOxUS98Q3p84/By9U/r4Wb5RvjGbu0pr12o/8ubPP8P38C/FkQ5ouP7eX6iodQe4V3diwkbsEETzN6i2/U0CZ9gu+nNvHr8EommwoMA4QkGKoSaXG5uftiCS60q5SVyY7YYgLBGi02RGyLKb4CI/e/A0/AJqZ0Ftk+4qZ7GrbZFg2BGrO1JuZYFaKYfCMxxLT6O5lkOvi8JhOVQXtshFVVl9v0I3kmvAo/koV6lOEvXUkh+Y/Mtwyen7CIYHONyTOyhG2bhliNYFOVi2oOjcEKMVXl4qrFdBMOzZjLBNPhh6nNLKgoNMPh4dR6/NM8TJAVfB4LzQeN8SpTHYONeoXb3j7AJbKJ4GSHz8ZX84n4SqK2Rbi1xK3xFYSVxt+SIWaZRG3XaHXMMHigI8ECgviRRJTOE+lt+H0mj7QmiOpBpvnbebAjQZOvylRLIFFMlkHQdN7dsQi/v8aPUluYoTXR0FxlYThDm2UhdYUIujrdk4tnEmis0txeptVXJvqTQ0QdgVe3kOEGItEiM80q4dYSorEBrcVHQDm0+ktMtmpo7UF8EffAaLQdPGGFt9ktt8YLtCmdNkvhCTlcJBtos6DZVyX6k0PsyBzhjvhqwp4KDUpywYVZLhvYRjMmTZOrTGgdAcBQrjEz0GFxge4aIy8wBUJC0FejKVghYlTYO3iciyyNWwaSyEgDHZ4ynoDF4lqViG0RnAYrVCPRaAFfyKS5vUxQCSKtRYwOd5202IqQsjg882LCTSXelVuP0CUair2TFtAq/fSZIzQ58M32BE+mt/PBmsUlWjNSU7RgMFVr4Kn0Dnryg0wRAWY6XtqmjlCy3TXlQzLw7osINtdot1wPloADH8wkaXJsZtVqtDSWODJ7Dh1aAz4Hdk9ciF/o3DKQJNBcc+fXCBEzHW6ILaWhrUaLVmOy8qJJxf6p81lYrfK1jgTLvXF8SA7lzjDb1rknnSROhcnKQ4fp8PneJDE9xFTHAMDrKFoDZX7eu4vJws8k6dqH7uhLsq5lOfG6isIQGrOrDg+kurg500lQCbyGzTQRpEmrEVCv21POxf+3xr8/Gm9mroz/KYTYL4Q4IIS449Xanll+EQ4Cx5TUlE2LZTNgFcCj893WBP6ojWzQuCu+hqC0XKOFUX/hQQvbktwXS1AQDl5pE5QepFDUqhoNtoMXRalmgKZhBNwNriloqE96k1Fl7ok9LDDdjRTQTR59toOwbdP31ukYStHQXMUElHN2YRhKoBCE0HA9r6H3tkcB16hULehUhg0cBDiufnZYkwgBunR4Od/9Et/qVYqmtjIPdCRAlxiaTVNLGQAZgA4LQug8/stWnrdz4MAZVSGqdBxc0TyuDEwBjdKHhsKoS39KgF/B3ekkOgIDuCa2GMcWOAJ6zREW6y18rjeJENBgOzj150PT+Yp+VowM4YrtusdhSuMInrACy30KqSl8TRbKAa/HYujTiykL8Bo2GDq2KXlLbhOOLUDTEEEfAWEjpaIoNITXGO0nLGtojTpOrT5PpiBsw02DnQgd5pgaHx1Iuv38z6XcHF/ON1PrsB1J2BE4tmD3xIVowh17MOpKJVUBXf0HkD6BF8mTkTU4AhxT4PG6byYaLY62fSqyGoCGhiq+iE2/8HBNbj3RnxzCFO68S12heR0qQjFtr+v98rPwatpVFa9weHykFU/AvbdoCNBi22iGQ7PwcDB3mlbr7PzulgG0+poKIMkqdwJuiC1FAxzhqv3X+CbhVQ5RRyJ0ge51MOtL1K9cT6CAcrARCOnev1l6CDquh9Na05XodL+7F2J6CEM5BISG9IDXsAgrgSYdfAGTt+Q20WJDGJ32upH0031Jvl03ugdepmkICoOX3qQGo/MadzQCaDzSmuAP4csJeEw89e9dIaM4wE8ja9gVd1NKBII1vAhGbIOWN0rA+0tUZQgh5gK34oZmzwfeJYSYfq72w/1+egxJedjALw32+jQ+qE3GShf46ECSSlbD7LXYaec4JP0c9GpQKIJt0d8TolT0cErUuD/VxXYtwKaBgwxVfJimxoAu6dUMirbBwA+6GUn72KyG2apXSOk6metmsJMGNkSX8QPRzwavj+X929kg8nR7dAaP+Tnp0ejpacISiuKwl2MewSWRqWx1suzySR5IdXFEFVGFIlv72vhkf5JyxcCyJNlMkLQhGTrtY9K2w5QFDBV8dBPgmtx6ug3IDfkpaJKH2xIM6hrVgs5hWcXqrbC0bwfDg35qw5LCaZ0DHocTToGsBnmnSm0QWoWXrLDY4tcojHg5JipksejqP8BBj4cew+UOj2k2t/cl+XD8cvLYmMBnqh7OFELs0Gs4KI7VxXjTkvQaElMINpv9YNZYcOZ58gUfH45fzhZrgP5UiKGcn8P5Ztp+3Y0qVxn861kM9fkZPBUkn/VxZiSEnSvRJ20sW+IMFcjmXNc6q6ahCiXsTJ5T0kt3qZFrs+uwUsPUhiVHZs+h4BjUei3squRLsbX0pRvZpJe5M76GckbjlK7cQ7nkpfmftnHCGuFD8csoWjo5qRhMB8kU/ZzGR77Hw6EX23h3x6JR4lU4oTGkamQ1yWHD4cyxZmZ172e46ONYOgxAVir6dQ0rNUwqG2L4tI9H9CyPt6xlbftcDokypZKHakFn8FQQDcG+KfOppSy6vRrHNR8v6D4OUmYoE+DRaAJVrFASkqERPyedApe2zmCz1+aOviRXdczntv4kG8w+spkg96e6eCq9A4B1+SOsM3vZqIboO9bIt1Ib6NV1TkmL0mkoZLyc1hUPtyXo1h2OWg2UhOSoxyCdayDd30hBWZw0FBuiy/ilXgCg92gjX+tIcMoaZotf49HUZkr9Or2VAH9giHLNINXXyCOtCboNxfPOEAdkhUtbZ/D5+BoGNLCUZIso0OVz+Hx8Dc+Xe3hBVtk7aQGnDMmZXCNTGts5JGuUsNlkVHnB4+VktYFjde+YPRQY0CUnPZLecpAeaVEseDisihSFRv8bpGNWyjnvz58CbxbHPBvYqpQq1V3nuoC/OldjX8DkiOZay8uOybKK6xQlPJJb4ysQQuFYMENrot2y8CtAOSjHxKPbVE1t1Eez0YG5kakMo1OquZyjRDEs3NNd9zjMkiEATumK6JOHCTpwQAaYrIfoqLOxLq8Jc47uwxQQ8Ji0OBKpKUIO7MueoEX6aaiLVhoCISXtTo3Px9cwUvPg2JKHpM6AVDhKcHjmxZQk1ByNRsfmu62J0RcwIsGjXE7esd17OjX4QTSB4wiOdEeRmsJB8cve5xkRDnmrTLYnwMOp9QgEjY5A0xweXJjhX1MbmBSKEjcd7k4nCWs+fPXeAmjkVJX70p3YShAxKkTQadR8eNC4IbYURwmqAnSl8EsPKIcN0WX4vK5+xxAaPo9FvurBxnUhEx6dlv84iG1LNN2hWtHxCXfDhZXGpb07ELrkoivzPBFZQ62qgRRIr46GQkPxzfYEQhdIXVEtG1iAXXXnY6IlsJUgiIaNQjMUReHQakPRcqWdqBZgWJn8h19gCmgIVXlLbhPv/qyXwoiXRm+VLwlBre7iJqSiomwE4FWCqZfkAMjbBoZwN2VROOQkCF2Mct5XyhY8SiERmEq5jEBFo1wxKAmFcgS93Y14FRhK8cn+JI+nt1KzNLxKgXIoSMmKzFZ+17uHy4x2WpX7DEq582Aqm1CD63F0c3w5740txq95udKI8cve5/H7a1wcmcJHB5IoFEKCEIqYLZhumjQpScBx6Nc1CgKCukWDt8ZT6R3YwMrMVkrK4snIGqRU3NmbZKLeiIliSmM7ji0wUFwggxwSAaRQ3DqQ5KupTnrNEXrsIiNWiTIOEjCVpEV4OerkiTqSuf4YNgqpKdosRZNR5V7PHEwUg6rK91ObCDjQISuElcbbOxZQUBZeBVLBY34TC0XN0ig4Na7PdvGl1/C1P2/8JXLMwH5glRCiRQgRAN7B2MgXhBAfE0LsEELs+D+ZsUEwe7ye8+7oJfHsfBC9pvWcdYvk2ICTh5aevzHm1XDrH2HP+4Z99Jx1sy4eG9jwd2/NnLPtJ3eFz7vPfzBy5932M+LcbX2B8zeSHHk2dN5tS/LcBiD7Jba3juF71p6z7X9+o3befe54WYDOa+HfZ5TPWRefOzKmvHfSgnO23VTrPe8+Hy+cO0jolWg3zj2+VwuGeiXmyvMPyPpN7+5z1j3oHB9TNl5l+z72isCaNxR/iTpmpdSLwAPA74DfALs5q0Z9qc1omOO79QuJKA3LcodTEgqvAqdk80hqI4PpBuyq67Z1TW49ZQGNf/9bhO7lkpN7+LHu572xxdwYW8YtA0n2Dh7n2qxrNLyjL8nNmc7RfoVU2CgmKy9fTndyfP4sThtwsuaKoOX6jLT+7AiWgBMLZ/K53iQ1S+PO3iRzT+yhxXZX04/TW5HA+2KX8lR6B8qyeUtuEx22q0M1PDZSKC4wBV6/5XIgCsL+Cv26qxu1cYMI7uhL8kL2FIc8iuEhPxEM7Ap4lMLrsxASzIpGg5IsiV7Et37XxlRvy2io+MOp9cQsEAKeTG/nA/HLOJ3PcNDrPtCQ454QX4kl2FRLIRC8u2MRG/pfZHn/dgBF8AgAACAASURBVB5IdRHVXBXDE+ltSKEoCZeLnaAFwaxxr9VOteZydc/17UNqiiwefuarcuH+F3EG3c274MzzGB6brVYTRaWjag6nRI3dExeiSjU8us2wJjkzEkIN5bHzNSpC0Ku7RLjl8YOYZUmh5CGjC0o5D2ZFUqvr5ms4fD21DuUINph99GiKM5qX2p4enkrvYIYIEkFnAPew+F14hWsMC9ZYkt7JdruRaN1WUMkb/Kp/Nx8dSNKgBOWMzkDFj1c4nJI+lkQvwkDgVe64EtnN1KoaBaHIS0mtoJG2C5yWXkolD+FIia+mOqnUdNp/281L2/q7rQnmnd7N8v7tTKCCqtl8KJPkicgaAKqOO9aZ4YlM1ULkJTRpfkbyrg74R6ktPJ3eSYsR4kJ/G++LXcqs7v1c6I1yc3w5zegox5W2tulV8kLDUJAxfUwwLWIWXDbgpioAsIQbWDRXNnJdtotAsMZ9sQTd1QyTbMnJkT6smsbbchv4VmoDmZqflZmt/Ci6lrvia2jVQ8zSmjiUO0NYadydTmJy9qDMSIeMXSKIjpCKqhT0mz72ZU8QwzMayPTBTJJex0eDAwXHNdwrzkaWfiu1gaqlM+RUeLxlLZ+Pr3lN+nNe+Ev1ylBK/ZtSarFSajWQAw6fq20gWKNRCZQj+H3fXgzceH2Az8ZX0xwtoRxIqTKPRhP4FQx9ZhloLpH4q2qNp9M7GVJVfhRdC7jGA49m8+22BPfFEtyQ7cLJuoTj66l1PFM7yR3x1XiCNg0OxGSFLeUz+F92QB6VJlOfP8TXOhKouspiW/sSClIwKRTlre3z+Fxvkp+kt/PujkU0f2Mrvwiv4jN9SR5rWYvUHIq2QVVCtawzq3s/JQn5ioeA4z6fJSDnePhua4Ir2+fx1VQngUCN06qCY0reP9hJbsSP0F2ie2+6E0vZdIsKBafKiYUzuTG2jJviy/lgJslwwccV7ZfQgMZzkctprR+HnX37WVm22UeR5zNH6bUKmDgsjF44Gsb7dHonFWxui6+iaBoMCpuKkGwunYKGZt6RW09LW5Hv1/OC1OruTGtNP0dmz8Ep1shcN4PDMy/GsSWzrAqDmg6WogWdvmIQpMB2JLcOJIl6K4iAH6ELBnSYY1VQQO+V09G9DlIommxFqKOKN2RxRLfpN31oCG6Pr0LqipjewJfTnRQlCI/7jrJ1s2oL+qha6JnwKhxbkIxcxoVmjdv7ktwYW4bucbAdh2fCq7izN4ltut4SBaVxgSqzI3OEZkcyIhUD77mIJyJr8AdN9jkjfCiTRPc6dPUfoM028fos8sMuIfX7THpWTOf2viQlKWi23YWVjFzGiGOMGkpfkgf2ZU8AcCh3hkdSG/lC2s2VoWsOb22fR0dDmJVtszmc76G73MdP0tvZ3LqUKSLAj1Jb2K/ySF1RKnmYb3uZ6i1QEYphqWEKMapTT1uu50xACX4dXsk2y5W8ZH2/TfaEOaK58+cNniVKTVqNX4RXURGCF1SBZ/v2jkbrdgtX3VIVkn9NbeAj8ct5INXl+kJjMTTi54SuRonNi8rVa78Ueh6hxhHNYkP/i0zVQlTrDZ+IrBmNbp2sN2EoNSbPxuvCX6gqAyFEW/3vZFz98v95tfYOrp/xDbGlGAqqQqEsRr0dACaJACHHoSRAhAKo0jDPT1hEzZG8tX0eE2QAqWBt+1yuz3YR8JtUhSsuPRlZw+C66uhGnWA0E1YSo0khgIJtULZrWPXuPhR3idW+KfOpCui1z/ojlySczmf4fd/e0f/9vHcXuU8t4l05d7HeNNhJJtNAe7DoBn4UveyeuBBDga0Edv25Gh3BiCbJafBx01VBVCsGIaFTK2n8NLIGn2ExeDxAKe9hQcs0dg8eI4JBX80VlUtYGAhXZy0Uz/XtI6p0rshuoiDdw02Tkj/4BU+kt3FJZCohzctvenfzv9QkfNpZYWYpjTycWo8hHRqVRrNj0e5phKwraheHvdwQWwpAuWaQ0yRNtkO1bCA8rs64WtEpFjyM1L1DnIrDRFviAMq0qda5tkzVB1Kgag4zqg5DymBIKjqe7aZW0mhoqFIVYlSa/GZqHQpXx9yoNEYyPuLCz6fiK4nYrr1gVngSDooFVcEBJ49palyV28jSBWlX6lCSjT7XV+DH6a3YdSmtx9C5N7YW3WtzSvfQLE16cN/5gLRpcQStPztCOzUKI16apYdvtyWYuzsFuBtJOQJHCd5ZJya1gs49sbVYwGGvZFXbHMpKJ6dpKNMNE78u6xKat7bPo+4hyI2xZS5HHJ6ElIqgNPBKDxv6XyQeaOHUSD+3xVfRGKrQWTnNV2IJXiz3Usp58PosbAHZig+JwKsUKV1jm1EjGbmMoHI7yQibrNRp0nx8oz2BUu7/GoUHDcHlrbPcKM+WtbyzYyFVR8NGYAmYIxqY3NjGDbGlvL3DVc/cF0vgVW4I9YBypbOb4svx1ElMSAkKUmNV2xwKdRebl7xODOkwydFZ0DINDTHqrXRDtov3Os0EPCYpK8/12S6+Ejt3OoQ/Cn+Jqow6nhRCvAD8HLhNKTV0roa35By8yg0xbRYGC6tVQkoifYL7U12uG5JH0aZ05kYHaXIYDRFuDJcxhGKxFqbfqRBQDp197i+8THiHRqulaLEhpCw0w8HwuQvzY7UQDUrQ9utumm3ISJ0J3jABBx5rWUszBhc5BoFQjSmmYnbE1Tn7PK5xYlHUdTL55styaQivwbfbEnwxtpanIquJhEt83fERsV0/6H2VJlotCBombbbFDbGlhB3XVzfgQKi+afz+GnvNDLrXoYUaXo/F4HAAr9/iSu9E3t2xiCYlmeB1CflHKkE68NBq2eiaQ++V03mRIjtii7moavH11Domh9poUpLcJxZygbcFpRQ3xZfz/sFOGgLuRvpea4IDlPhsfDVBr8kONURA2AjEqHTib6gxiwCfi6+mMVhhkmXiVYq5J/Yggl6kT6MxWiEQqOHHZrJVo+3X3e7zaSbC72HWGldXPaGhAFIifC5X1yhM3h88y8EpdZbTlPXkAT4cJAINV4KIK4NvpTZQE+4m90mDqcpLu6pxiWzEMGw2RpfhXzWJYKRKGY1rtWG+0Z7gnR0L0XSXmLRZDl9Kd1LJGzQ4iiHHYAIVN8/Fy7bJUz4DpQR+NDpMm+kNcT4VX0lQM3miGqYhWGWKDGIYNhfsOch96U5abEWbBRfrEd6RW8/NmU6+/rtWCtJlGN4bW8wyGaG5riLrsfNMEH6melvwB0xahY93NczgivZLOJhz0/oGkBiGzWPBZmZXHa4KTMMTsPjPcgthG+JNBRrqa6rVcphne/iZzyBY54YlLvNwuWqkre6m16AkPqExz9RYbbSj+x2ijoUDHNW8vCe3Dq8CXQkWBSfxRHobBafK22s+wjaEtRpPprfzTHonX4ytZV2+m/8nNETIXyXgQINj82HVzqVahLe2zyOAxj+3JxBAg4KPa1Nox0PYhtvjq7g7vpaw5abvbdddv+cvvCyXzevCXyrHrJRapZSao5Sar5R69tXa/rBjrAXgoMd7zrb7M2Mzg1XL50730fOrsU6PkavPGv+e843tc45vrKHmrpmp0et+fayRKWqd22Ixyxqbaesuf2H0+tLmsQa7ZSo4pvw1z/DodcLoGFM3ITY8pvzp1WeNRU/6x+rB7nwxes7xhf91bAa+a2NnM969lK70JbyVcxsRd9pjjaOnl844R8v/mkktvcN/7rZDwXPWvTJ5VEP43FnNnnuFAbn2/Jlzts05Y+8zy392rj/eP3ZObrTGGtN+ufDsWvhAeKyBNrVqrIfoR9XZ737unWPnb48au/5ejleGVLw889sXrbHG0RtCA2PKGmcJy/tqYy3Rr2b8e0EVxpSXeIbP0RJ+4xk7fy/5NAP8cGSswf2Va+zlZO9ncqxx+aupznP2+XqhlH3enz8F/iwi/4rDXk5qNmZFY0s1RUG4Wd6kT+O+WIJqQYd6Fjb5kpuTriEMP44t0aTD/akuGoTBoKYxrSnGM+FVlCsGI5pAARUkTfevx6q6C3lA1eiVDj0rpiNw8yj7pEFBupxER7KbUj1wwARqVZ1PxVdSszQOeaBZ83NDbCkSWBi9EIDmb2xlTXYzPgSGUmi6Q7HopV+XmKaG1BSmANPWGJEamnI3vgeHZlvhreevsCyNEg5GwOaM9FKpGvjDJspxs6oB/NO6DpRS5LOuuH1/qouylFi25LRdYC5BSjWDfl3nK7EEx4d7qQpX5HwmvZPf9+2lqExGnBoD+SCfirub1Kob1obKXgakQ17peIQO/gZ+Fl6NWdEYFDadffuRmqIkpNtvVSJ0ibIcysMGlqXhkza6UER/cohBzSUwQpcM5IP8NLKGoZKrygBX164JhS4dMu+biRGwufjYXoY0idShMqTzud4kTUaVAWrcm+7E8DtkX3LHsy0G/3oWE4wmeoTJvKrCr1zVQtHW2bqhg5EBH3FviXQxiABCwoOQiulaIxLFV2MJIhdVKFcNQsJydcG46qaigMGbZlO1dEJNFXTcjIFODco4mI6kXHTzoTSiMat7P8oWfKM9gaEUHx1I8tFajo3RZW5KUilotRRRXPvIz3t3MaAL7oivZn3/C3wztY5Bu0S1rHPaKY26RE5vjhOSXoaxqFZ0poogA7rExEE5gmpZpypcI6BHQUa6ibKqwk2wpUmHd3YsJKo0BIrdosRNg514gxb3pTvpd8oMaPBCOU1xwINP2ASEjiYdnotczi0DSUyheDq9kw/HL+d0JUsIndv6kwzbHq6JLWZIurpzB0WPqFGpG4xDwuLiyBS+muqkUXoJIplSs7GVoF8qftO7mzNUyWuuRPBkZA03ZLvweSziws+vwqv46hulyrCt8//8CfBnQZhbJhd5MLWOWd37adR8mMJNRWhlrdE0nKWsh0XR6VSEdAetaShlM/fEHvrq+SgeT291N0BgFtfk1lOqGXy8P4klYFhzCbKqMzg/Tm+likMx46Vfh1+EV/Fc3z6UcA0018Uu5QvpJNWKTkpazDu9m2+lNrAkvZOoLeg1h3kivY3b+5KcKp7llDZEl3F3Okm3R6cw4kUpqAiwbImQikEN9soAxzyCnHRTf1aEdDeHkDzQkaBW03gotZ74+m505RqScj0BcsMBepwSb3ea8CDo6j9AKFJhqB4VJpWiaOlM1UJ8Kd3J6sEtHDIchurEy68ENoqrOuZzVcd8nk7v5Nm+veRw1QE3x5ezbsTN9TuiDPI4vCu33k2UnxvgPTnX02Wo7u3QGK1gKMUJQ3DBnoPYAy6XNat7P8MFH0oJjuhe+q+eTl4oVmS2oiyH1lCR67NdREJlnP4hVMnGxvVRXt6/HSEFeoObA/ijA0lGUl78EYuH2xJkTR+PpbZwW3wVtaLGyToXOqxp1Hot9hZPU8LmftnDMVFlztF91JDs9+p4vDb77BBX5zZQFfU1UNb5Q/EYFSHdXx057KfX9jGIh7TuEpQh6YYYtzz2ImnhZSjn55hT4HutCaojGt9PbSKvdAolL/mCl/tTXZxZfhFW1U1bq4B/aUuwe/AYKzJbuTq3gdrxIhHHYk12Mwta3Hwbw1IxjMWt8RVcE1vM9oHDbqInFHMikxm0CgzXijzXt4/JysNAPkivctUENRyGB/2cKITo1xTzTu/mtv4kaV3U/fgVQWHRb/o4XhskI2yuym1kW+nUGGIXEDoeBbrQKOU9rMluJiR05p3eze98Bk9G1owaV0NoaELS47gpEfo1HQNJXij6hEXVNkk7JcqmQVpTpIWXRs3P+2KX0m+7e35Q11g9uIUR4XBNbDE7Kj1UBQxiUZKCu+NrKVbd9Vmuv6M3BP9/1jH/3362WwixQAixRQixu+6nvPQ17yNdd6KD0+eiIflCOkkEHWW9VK/whSymGxE3PNpWYLib5uTimUzQ3YVxY2wZd8fXsg+33NJY4iuxBH4HpqgKR2bPwfDZXNUxn1vjK3gotR5PwKLNglJdZ91kKzzSYZpwXccMwyb8stzEL1x4CUd1G/tlL2ywfNbHc2VmKwBBBxoaq3yg1keTA7rmIAS02K4x8u50kkYl+E5qI1UhWdeynE9WXBHf9zLVRMixcWzXY0XXHHbkj3NAN/ErCHp8eBttQsLg5vhyIspECvhyfBBwD4nZpuTB1DoWRi/EQRFQgoDQmSDPqgwmGW6035BTo684xIfjlwPQUF8e74+dTZKuexwi9UBbI+jgwx4NwxU+HRn0cGT2HGwlCHhMfA6U+zUurLsFCL+H1mluf7WahvB7cCqOG2BSD95AghaQSKFY17Ic3WtTFyZokGfnxhO0aRGuyqLRdlCOa5Q9Zef5sh2jAY29kxbwrtx6PnW7D91rM8Fyv/9SCLBSAtMxSRmCu+Jr0HWHjKbhUw5R2+btHQvo42yfbaqGUoKYDNBoO7zvjHujADYNgSo+j8VN8eUITY16Ovj+L5u7/ffdowEs/VXX/NJmC8LoPJLaSMZy52hRahcGkha9gd2Dx2jyBGkPNtPsgKUEeVXDqxQV5aBpzqgO/iVUhdt/QAnWZDdTlBovZE+NtpgXiLsh+n6Hu+NrXXsCoAmJx2vxq/AqGuvZgWsoTCGw6lKrgeDYcBq/0LkvlqDBcYgLH3vUCGUcMqURGoUHv2ESUoKqEGweOIiFokXzEw2cTcYUVhIfGicL/QxKRQiN5zw1KjiUbJ3LW2dxXbZrzFp8XfgjfsHkT4HXyzE/yn/92e5/BO5VSi0Avlgvvyq+cqSDvITuwTCfsF2d1P2pLoIfWgtAIGyy4Wicv6l4WdAxQEkKdt8/gP3TRzECNsv7twMuB3RFucbjaZc4TnyPlzbbTegya3kGzXD4+74wt1cbubYsebAjwXf6Yly97DRl6SaBudc6zNMeH19LdbGtfQmRmRUurdjsnzqfoU8vJjyxzExL4zr/dPre5uoQ74i7eRROLZnBE5E1fDWWIGw77O5t5WDuNJdo7k/zHE1HqErIafCr8Co2iDw/iCZ4xx0eVg9u4W25DewWJRpbK9wXS9D3tums+qRgRyVMqWxQNnWebZ2ChnA9PWoV+o6GuL7iIYxBxF9hm8dLYJIrAcy9STFTuYfUNcYkdpLn1utHmCNCXF0x+Fh8Bds7lriuce+fxYdqIW6OL2e/maFFq1Ktb8DbLcXDdx4hGbmMU73NfPW7a7kzvgazKPlPv+R5rcqR2XO477cRKkdKZDINxNtHeER6ueri0/xDuoW0DnfH17Lr+xI9ItnWvoSmSBlVNdHbvOz1KC5+yxBHZru/pPH7dXGmX56j7Oh4G2ySuyZSkNAcqLC2fS6JisSuCZpwVUy9hkZ8fTcbo8t4yKPTrNWY4Og0Rsuu6kC5on7EW+Ej8csJOa6x8+Jje7k2NJvP9Sb526kpWhbYGAqGpUZBSt6mwiyxvHyzPcG29iU87dMIR0p8469t3nJzmal6k5sT28jxkNlAQ2MVDUHn/8vem0fLWdX53p/9jDWec+qcOkNVckjITEImSAgJGU6hImqL2g4NbSt626kdEKVtbF9aL8ql4dq0NooTrS3N5QW1aUQRWtCcEzKHkIRA5pAQklSdeazxmfb7x35SSbgG0q/cdd/FfX9rZa1T9exUPbWfPfz27/f9fb/7JzPWH+XWTBfdUUGTr7zeu9tzbM9cyhezq+kPN5XPJxbyw7YcsQDGQm+0y+zgV6lV/KQ1x697dxARBo+nVnGTNZslyQupCPhFVKn2GFLSG5T4m5rG5oiJJeHu9hz3pXMsrLnstU0CoTDscyLjfC67imuDMh2JFK0iwj1tObLrDzPJE0wRURIB/I02jWR7lX22QQmf36ZWMs1XYbw5gc1HsytISZ0bsqt4pxvjlkI3x02NGqqy9s01i7/MruC/xio0NlZ5T2M/v7MqPNy8hpt9wRWygT9tmo8mVe7gE7NOcJUX569bLseU8MnEMFE0TsgqxwyLPzEyrG1ewS3RcxfM/Kfsjewxn0O2WwKntsJGIM9r2F+nVVJsbucA9xpDPNDSxYezy3GePC2F86bLTrAlqo5XAAtvSKC/5y8oD1l1yaZT0kOLWqbxRGolR/9NDfKHWrrYvinDtN37+fvsMLsiBr+LKs/gMxeeYPOmLIujI3xieyO36bN4e9Vh8D2z2OsnqfTqnAy98394OMl4IYIdwL2jO/nO7sln/Y4Lth9kboPyft43vI5LO/vYP+NidgRJjl06m6mt6tpbjFHePrKet3uqAm7/d4d5NLWaD2Yv58HCVkYKsXoIZ8v3A95y4UkmTR+jc/Io/+woJrTrr+7nqo6FZC6a4GchXejxSoJ3xoa4dWs7+2yDpn/aRiEM89wztoN3ew00fVcB+9dGfDLSZGnvdtLJMi0P7uc2TSXILjPbidsuF4WJpftMi898fwnfMItMyY7wxY+t5Ui44L+/6vP+ik7DZIevfVhiT4uwfGAbAJ+QVQ4+38pdb1GJo3f7RS653qdvZ4QhJ8LwYBytQXnuKyuS555q5rk+tTFfN9RD66OHeOvIBvSoZM3FJ7g5VBl5s9aqOLlRC9lyx6DD9Rm9YQlXDG7lEa+p7n17NZ2OWJld/ziGbgboWlDXZ9xiOhxdOIf+MBT0/aOT8IseC+0xZhpF5hhF7vcVCiIewPQ3l7jOVX3dfZ/i5vjuxSNM2niY71oRbm5SyavJ2CxpGSQ9vcQsB5bWNJKBz8+SKVaboywpPMvf/Ynqk43pZWwTRT7Z340r4Mf5TVwTVh7+0C7SlSnwqTD+/y+RKv83Sn5pSAv468RYve1KLc0PJ5f48yYVVntTfEhtZIbDNMenxT+NaHCR/IdI8kh0JqPS4ULX49ilKkHbSw1LwjZLzZ3LvTKTpEUmUeSzfd18rdBTfw554XJ3fj1bLOVVznY8YujM8DTypuDZWi8/qCipsM1DbXzO97jPLnK/EWG/VmNaYGFKyWomeGJvJ4/qqk/mODD74At8L6/0Oy+PDddDGD3FV5cFO2/7PxCVcSPwTSHEceAfgL99rf9QHrf5Ql8303bvJyoMPjjUg4nAH1VHyLG+COVendvzPbxcTOIIkMPjIANm7N3LTeEi8dDILvo0ixYjwdtGNiCE5JNhnE0gGb1hCbWSoiicwGe7KFMZsagJQdUxeKSwnWuHesgNb+YLW5vZZwVUJxQW13F0biv0MPvgC3xksJvJsTQbgkF+2JajN8RtjnxasWGdGkRSghXzcAVsPdqBpge4wEaniYeb13DCkFw/2M1lfdtVIklKxSqHIrdv/+1h3jqygecPteNWNF4+nmKj28s2t5/m+/bwZO9zFAsmDxW2UiHgXSNP0zea4Dv59Xypt5vnpyysZ70Hy+P1v3cEozSh1zX+5h97jpuzaxh1S9yf38KhYJzxis1uw2NDehk/yG+A8RHW9j0fJkMDdlfyuFWN3PBm9tgG7U8dxi8MI8see6fP5+XeJr4vbNYMb8brrzHb8TnuxiGQzDuym0HdwA8EyAB/1GFE14kZLr2mhjfsceJyJT30WGoV7oSGF5ZkHi02kBcuGuCUDX6U38iHBnt418jTNN29nbd1LGZI+Jz0o5zUPGbs3UupZnKcCEY0YJfbyC2ZLkZ0pYFXGrMZCpQXdluhh6AKVcfgsr7tPCWS7Bg8TEGXjOvQ8sA+JjyTvv4kn/f2c1dHDunBzdk1jJUjTIxF6OtPMobP7IMvUBvVGdYFL1gqVPY3NY2Rstoog7EavYagEETwwydjSoVoGPBK3J7vUZwow1F+kN/AU327OeQMsa94ggB1opx98AUc6bM1hNiPD0aZuW8vBc3nkUoLn+nv5rgfVQnaMHax+OQOHh59Hg/J8oFtzCbOMdPAsANOGpIoOidNeKx4kMDVGPEtTgqHo8UGHmrp4rvtOb6UXcPJoEQlvO9ThSZlofHt/NPsMTy+1NtNi5Ggp3aCgeE4J00oODF+FRYx2WjsEmUqmmDCsdhtKtL955jAPJUICq0Snu5cqTHxeq1Yb2SP+Rz2V8AXpJSdwBeAH/+hRmdyZcw9sok7O3IcnD2P3/Tu5IGWLq5wbfQG5ak2ZStE02pX7jUMNECbNhkMiz3TFnBHkOSqjoW8qeki2gOHk84Iv0utQNcDvtmRY6rrExE+o+snsGI+H8hcRgM6Dxa2MmPvXjTANALe2XEJD7Z08dvUSu7Pb+HO/DoiSVfFnS2fm7NreH7KQu5py7Fz8EXm6Sk+2d9NLURKpL63g96xeL1stFoyOXGyiQ43YMWsPK6j0xgoIvaE9Lm10MP323JsaVvKgy1dPFjYSjaE4vVrPgPvnMmjqdV0NoxjxnymzRhijtmMLwPu6Mgxv3kqVkhjem9+Iw+2dNHeVOSj2RV8NdPFWClCIE7HG3sNteA3CbterrytfQnPdKgTx9ExBcF7svc5GmNVZvgGKwe3qiKC5lY2ppdRLZtYaBwaPUm1ZLKtfQkX11wG3jUTva0RNPA9jcmtY/zXyYNsa1+C0Wazx9aZYhdBBuo9CclEDYSG3mCSDAIcX+ezfd0YTQZmUvVDANgtAYEvuLs9x6RIiQgaX+rtJtLgcke4ka0Lqxef6N1Jg9RpxaEWLhxl36A1cHHLOovMMW4r9NQHfrKlWi94uLMjh2bBbhGnu3k5q90yi9PTaQkEjT4Mf/RiJILWliLvT8yh0wm4dm+EO/PraIxVSTZW6Zw6QuQUXWdWoW3mOUpBJyEMWhvKPNOxBOOCZrJuwGSjXC9PntBhp+EyNeSHXtU2F8v2uDm7hg9kLmPX0BEGy+M80buTOzpyHJh1MSlhc5GrMSZ8UtkyRxfOoTPQeYc2xjcyOQIhiMmAJl/xLwPkGmdzRFR5pmMJP6scYorr4dU0bAkvBUViAeQSKiHZoLkEQJNwmR0Zp8WTVAkY8Io0hrHnj2SXc0dHjogMuCm7uu6oDHgTvNW+gPbWCWpI0npNJf6CKhN4PFTYqorJpEZHoDPFbqFV1jrfugAAIABJREFURCiF4giPpVbxxexqTCNgnzeCjzhLm/GPMs87/3//G+x/xcJ8PfDv4d+/QFF//k92JleGpsUxgFpVPehEEDCmgTfs8bnsKtyyjh9CJX2hUA4Nn/93kAGGEWAZPklhUZIuJ3Sbl4v9lDCoVE1qAkZ0nROazUh/nOKITauwGQ1jeb1vmkFR01jvNfLr3h1cN9TDhNB5b2YpX8yuVpL0plC8DbiMlyL065I1bfMYxeX2TA5PBixrVUfBYWEyhq9ityWb1UNbGDA0quMmfSMJxjWo+joHLJNvt+cY0uHy/mcYMAR3deR42nLxPB0XiV+UVDSNStVk274s5VEVS94+eIiKkMyyW9HM0zt6APSPxrlzYT/HhUPZN5jQRN0LLwiPk5pHGY/+ELt7Wd92/EBQQ/Km9gVckp7BR7MrGC5H63wF/9G7C4KAQd9mvGIzIh3e1L6AYtHG8XXGNIPCjjiyUsMf9+qUpwMnEhRdC2+whhtyYvtDJaYsGuW6oR76R+PImoM37OAIQSkIieV/tp/qsAqjTGg67jjUigY39HVTc426+Glx0Ga/pn5HSZ7Gs1dEwAAWMXT2Tp8PwLLPWQSeqHNF3NTbXa/Qazfi3NWRo1/zyT+fpKjBaJjg3Dn4IqOaZEyHYNTBR3E8+0BZ09AQXN2xCNfTmRiLMJhP1FELBzY3M2IIiprguqEeflF4hkrVZKxmIR2PvKlR8Yx6snVEgxoB42FopSo9PEdnEJefF1R4KB1rIGlFGdUCXEfn533PUNZgUDpURk1KYwrm6AeCvyt0UxWqynTIgPGKzdMtlzNFRBkNHJb2bieqW7gIqhOKFW9/uUBRg18O76ZWNBgPTApBmTFpcLwc52Xz9Eafl1WmNWYw0SgKBZ3c5g2y31FY6pdL/QziUpqwMRFUfJ01QQJDaLhScm1mGRM6TITMjy/XhhmQVSZ0+FJ2DY9EfXb4w5RrJkNekYp4/Zar/xNxzHngFNPIlcChV2n7B+2Ydf6SMqXi+TPRTfvQuYsXVmhnA/y/t+DcTGr/mU57LLXqvNve9CrewOIpZ0u7f/6qgXO0hL957twseq+0UxWM52M3c/Sc15LN5y72eKU9v63tvNv2nrEQvNJOVXGespFPLT5HS3jinvNnIZxdO38v6b4p56YPnLFw6KzXW9qWnrPtKcjc+djS1Pk/s+bXCYebEOe/QH3AmnrOa5/tO3uMi1d5LO+t/C+Ulnojx5j/kGw3iiD/LiHEc8DtwCde63N2dy4iEYBuqE6wpYIzCQO+k1+P7wr0CHw6u5IGX3FbjP/3P4EgwLJ8YjHF3zxJiyGA2Y2TsQjQNImLRJdK2gZDxzACxsNj/K2ZLjp+f5iIlGivGCHv3mHwj6GsFSivthkTy/BJSIUhtlC4SkNoNOsxRm9YwgeG19GIEhqN2C4tRg1DgmYEJG0HW0IkJKy/sa+bqFR8HLpUk/Pe/EYMw1fZeQ2uHepBCFWirOkB0RB4/6PftjEe1AhcjU9kr6jfZ254M61Y2GgYQqmX3NzbzZSGdkwE38mvJ45BmxZhcXo6OwaVPqAG/L5vNzsGDzM7sKlKvc5LsLR1FgQBd3IhtuEzIV2KQY1Y1MU2fAwpMewANIHeoOKzhhE+G8NFbzAwwuO9sHR0IflpOkdLvIKI2ghD4AiBc8ZwNOyAHdlLSPmqHPuU8kfUcomH7WQg6EBtzAJZr2qsENAgPSIInJrBVSMbufyCAroZ0Jwq17+jRYsgA7DQGRcSG42O2ROkdIek9AikYE6qEwNBIlCdZBBgWAFDOGrcmAENwsLzNWJxh3hCebs7spcofmR5mqjoI24v0YhLFR1kQKsnSVguO2u97Bo6giWVMkgyRGuYKMjaKU6Jj2SXM1geRyA4JqvYUZd3tiv+lSo+mhFghITzhh6GcULa1BYPNCGJWS4HZJF5WpIN6WVMtZpVe8snKTWiuoUpYVXT7Pq4iAhVjJIUHjf3dhNDY7LRyBxiHBkrABALy+Snh2GYb2RyNFoJTASRiMuFjkQTSjGnUZhMSIeHCluRQqn2VIQkaURxw5juN/PrOGwZ9PS9gG167B1+GfP1jPe+kWPMUsrrpJQZKaUppZwcMsptCFnlFkopl0kpn32tz1lwfBej4Z1c2T4fD5jQQIvp3JhdjW5K/KqiALSkJB6g2LlC/oZa1eAXhWeoEpAIAnYOvkhJ6ASB4NZCD4kgqP9QM+LRgEkSAxNBYc0MakLg+Vr9yP++4XXMNFPcHfJgeEh2ZC+hSoBtepwSUahKn3vaciSFiS00mu7ezo7sJegI3EDD83SEkHViJMvwGT+jx+9py3FE8xgrKdpDR3rc2ZFDN5T+nxtmOnQtwHc1nJqBjuDf7CqugKf6duO7Cgv9l9kV2FKypW0px2SFMj5GiJP9ZkeORjNGR6Bzc3YNDxa2EkNnptnC2zoWU3RNivgsSc9kUcs0vtzbTUJzGRcBDzev4ZkBRQxoIonYLm1alIgwkBJqno6OUhMPxiqgCfZMW0CpaBP4gpe9GEFZLRYRw0PYJqYWIECFFQwdvdnGkIpi9K6OHEMfvAiE5JL8DgIg8NRC/f22HBXHpBTGjnUzoIrkmx05ykJn8L2qVLmMz5CmQhGLTuxkQ3qZYqszJKOjUba1L+Hb7adFCgp+kU5PMIiLV1KVoqaQeFLD0lToZFwDrcFCIpgYi9BJhGuHetAMiAldUWrWdHxfkEDHNH38KjiC+njptFIMjceI4CMd1ScV12DX0BEWtFyIgWI+fKiwlZuza2gz4riuTpWA6zLLyIeFHBrQKiyqZZNfFp7lk/3dxISBpiupr8m+xp5KI1/LdCGBIUOr09kuKTxLVXpMEKALSVV6vGtEUaiaEmK6rSoG/TLVsklNCFLCJqL7VMJw0Z35deypFHhGKhRFKybVMLzUgOqvipCUvAo/ym9kfCLCkCEoSh0dQRMmplAiGBlXYdgnREBEGMSFCj/ekunihr5urslcSjWUfKsKrZ5T+KPtjewxv152cPY8mgLqzGiWRHELa4Ipvo4R8dEs+FR2Je8dXqf8B0NHRBuwoy6RqMsXs6sZCWo043BN5lJacGhIVhX9JpIOrcrQr3qxYj735NcTQ8MHMusO0+T7XNa3ne2iyK9Sq/hVahWtmNwQHrskEEjB1EBxyyYCWNY6G00IohL+Nb+ZuFALQSzmEJWC1UOK5DtmuzT5EjMSkGxWw1fX1MNu8SUZaZCIKD2NvxPTuLm3m4bWKl/NdNVFACzLx0p4JFI1RvGo4NUJxsvjFjdkV9GIwfuG15FqqjCHGDF0bhSDpH1VQDPkjJMMIBWEiz0CHcFXfZOE6fKj/EYuNJuohAosqUSFRqlhy4BrM8tA02g2q0RiLjqCaUYjDekqcdulVavRm5uBllTwgHlHdpNsrBJNOKroJaIzyVPxbGGbxCyXlO9hWx7CthC6gpOldIdGHzTbwAiFtCd5LkYCdFupgEQtl0HpcE9bDjPqk5IaqZCkKv2w2kBi6EzVytghVWvcdhEaVMZMLFNpC7oCfprfrMiSkLxkSH6U34jvaqGyh05NarQbSeIy9Ji9gEazRjxxOnxx/YE4JhovTF2IZfvEGhwuCAzmH3sOs1nwhb5uOnxXUQRIl6jpEiAQUYt04JFKVJjRlGX30FHOVE26M7+OXxaexTR9slgkhUGHpoqeqtJjQDrMP/ZcnQWxHQszGqCbCvnzwaEemgJBRAZMcj06XY+Vg1vZ0raUZhEhJdVmMlVL8HDzGqyYRyKAyUYjjQFsHthPIlWlRTikMTENnwsaVbjvM9lVXBa7gIWaQsWaEi7wBLYMcJDYCDp8wbxEp0oKWh4pX9IZK1GVPjE0ytJjirQUeZXmcoGvs8hQULg2T5IOBE+3XE4Mg6ZQxeUDw+t43YIbb2SP+fWyWQf2cGdtP3MOqwLCjw90c/1gN06vxxf6uuk72kB+XwM/yG9gY3oZO02Phr95DFkeJd/XSKlkK36HoMoOK8KvCs+qI/1Sjw8O9fCe4af5V8tgsC/B5C0q5H17vodDospLi2czrmt8NdPFLwrPcM3Ieq4ZWc9d+ae5IcRFx6RgqBrlpt5uxksRPjbQzdaBAzyQ31InZTmltjDn8At1vGjVMfhbVyV/Orcd5OTJRl7SXC7rU/pt1w71cEuhm0UndvK85XPdUA/XZZYx2hvj64Ueeo+pgX98LMnuvR0M98b59cR+fll4tp6dLpVsltX0etjlpYEmvl7o4Qf5DXzNz3LcNLh+sJuTE0McMXw+/iaFvHjaybN2/ADLB7bVC3R+UXiGAyMnEMDuYortjLPPNniosBV8j8v7n2FsNMq/5DfxL/lN5F9uZPHJHTxlRtm9qx10nZYH9gEwOBivi65e22Px+1BJQ05UuCS/g2tG1nNsvAE5OkHtaJmXLYMrBlVJffGFGuVeg23tS5gQOsWTJpUR5TVdkt/BhSKquBn6o+xkgo8NdLMtYnFyhYLY/b7yEnk/ygEqPNTSxUTVIvHWKUyMRTCMgH8SJl8K+298MEpKi3JbCB2c8uwBvphdzdtGNqABTw/tY5co81f93XiDDl8RVQoDDdye7+ET2St4svc57s1v5OKXnmP2wRcYHYgxJtQJa/PTHdyYXc2jUXjZMtjQv4/L+raT1y2avrWVt45soDCe4PCogvq/rPt1gqJT1KovDzXyy8oRHhvfxwFXlQys799bL6IqS5+723N0OyeZ6Lf5wUA7h3SXn6ZzHNJd1kfUJF8f1ehqv5g+N8pDha3sQZXP/yi/kWcjgvHBKI9ro/T7JbaYKhzTn0/SK202uH18uDbAxS89x93tOXa4AzxU2ModITdyUyD42EA3Y5rOD/IbOCoU3/W6/j085B5jZyXFS6Zgd62Rq2QTt+d7eLL3OW4pdHPIUk7MjX3dfCe/nqcnDrHHktzY181PbMFDha0cGTtdIfil1wuV8f9zZby2bUifXWb5tUzXOdvuC0ulT9ma4c3nbNvy4NkSPDPefu4E1dfDifmH7JUQnVtf5f5eab/p3XnOa3e+yrHsw6EndMrao+WzXr+0+DRj2weHes77fj67tuGs16+WdGoSZydWl7fOOWfbq0Y2nvPa/ReXz3nttewF+9zJP6d2NrPgpE2n88xj+tlD+3/cc+7k1a97d5z1+vLqub/zU27zWa9P4a1BFYucafMvODtBe0r1+Q9ZS/TcclunqD7Px9ZUzvbwms+gEzhFh3vK/jOJ6e8z6ZzXvlM9e57dmz/3WPjCK5J/4+L0/S5Jzzzr2k/z557bf7S9UUMZQohOIUS3EGKvEGKPEOLz4fs/C3kydgkhXhJCnFsALLTGeJV3xE9nmltC2R+jSXB7JkdTukxTusxHsyto8gMuCGFVwo6zI3sJfTXFMTHfaKbRV8mqX6VW8UzHEm7P5PhpOsfbqjp6WyMHZ88DFEnSdGljJXyMM46QP02rxfIj2eU0SJ0Xpi4EFKTn09mVeIFGhy9osGNcm1nG7ZlcXdZq9IbTmGBQUj7b2pcQCJWRb0pUaTsD1jXdCbgl08Xa5hVc5OrMaMryYGErQpMkMcjOGOOujhwR4dOSKSGEZGYsA8DUnQcAWNq7nWsyl/KhUA2iLVbm/Zml3Jrp4l0jT5MIJLeEG0mL1EkJk3d0LKbdSLKyYSZRzeKR5tUAtMebuC+do0xARjo0Y9LpKhgdhMfbeK1egt7YUOGx1CrW1BweaukCGdQpPiuegVMzeGfHJegxwZSQdF4kbNY2rzjd4VEba7JNwj+9UMSma1z43H4ilkenJ4g0eJiRgNsyOZ5MXcHt+R6u7lhEc0eJJmHxlWwXc2qnJ9AkK1UvUrh2qAcplThpqrVMsWxxf34LN4W/IZpwWJKeybfCfMKxS2fTivIYBZLORCvTiSoejY4IWa1KKl7hbR2LyUgTMynr4YRktEYs7lAUAXbEw0p4TPN15vombW7A570qT6auIOMr3PcpLu/WWCPTEhlmezpvMbMAXESMuBWhNaZOGhfFJxMRZ29Ea5tX4BKgSxhyJog2unQ2jDPHN1loj9GEQcqHotDo9NVUbxIq8X0JSSIoD/32fA/JlipZLcawW2R6oDbkdHsRW0qSuo2uBTyZuoJYACvMNt6bWcr85qkA/HlsNl/OriEmAz6RvaLucHS1X8wV9iTmGhNEJLT4HktbZ6m5ZSsHa4qv8dvUSr6a6UIXGjNjmXq8+tHUar6YXU1nrMTVHYvqc/N1sTfqwgx4wE1SyrnA5cBnhBBzpZR/JqVcFHJlPMxpTPM5bf6x5/hOfj3bM5eytHUWNaFUN4Kq5CuFbob6E5THFRbyfcPr2CnKdeHNS/I7mBrGvr6X38DHBrrprQ5zzch6lvZu5yuFbvoMKGoajXdupFyyuCm7mh/lN/KiqDHRF+FYCMn6bnuOjwyqHf2n+c3cVujh4peUpt77htfxvfwGfJSm2nitzEOFrXyl0M0vC8/yUGErTXdvr+NkT9llfdtxBTxgRMiPJc7yzJ+3BbcVerhyeBNHTFk/0vquxj359RT7bZUIlQbVCRPDCFjb9zwLWi6sf8b2zKVnESqNVCJkRISvFXp4NLWa46aoFzz0C58JPH4/uAdP+hysDSAAF8GnsyvpK41y/WA3d+fXc+XwJgZwKGqCiNBBN3i4eQ3Vqsm3w7BJtWLWFVumGUUwDdK/OFC/F6FJlguVpd/kD3JnR45gokoiPCr/j4gDlRreYI0Bg/pnBUWfY5fOZqgUxRHUMVW3FLoZ0ExuyXTxH727mBiKUJIet+d7OGhr9bLitX3PkwgC9LC4ZhCLYc1goDdBLVTTNsM+GRqI40iPYjgTpjx7gD6h+MANoZ7JSeGoY3sgGfYtFhzfxRO9O4lJQWVQZyjUU1xwfBeFgQYOBBOUShaaATf0dTOqwXFLY33/Xq4a2chJw0QYghv7uoloPm2RJp4ZOMg+w68X/uyjTMmpUnN1PpJdzqFKLz4B85unsrLtIgB0JAlh4AiYGe3Arej0jcfZoVfpLccoE3DcCPCF4EioUnPqhNkTDPHmkU0sMlv5bnuOyphJgKTZTDAR9ndfoYGyplEJXMq+QrcUNdjs9rNx4nBdDmsPRe7Ir6MsNF70J+ol2z19LxBBMBYqqQMkNZsJ6TFeK3Nl+3w+29fNW0c28PVCD1sHDtDrjDHNV3OoommUCag6Bv/Ru4tAUN9Q/2h7o8aYpZQFKeWO8O8JYB+cPu8IIQTwAeDB1/qs36VWcHXHIpYUnqW/NsaXeruV2KZHWPnjE004/Ci/kQdaupgkbBpv60HWSmxpW0o1PNLObb4AUAxjcBo3+qKmFpjDc+cSibjclX+aj2SX86/5zcw++EI9VHEmxvJUjG/PtAV8MRwMN2VXEzNcIui0xtSC8632HFMa2uuE8+YZMk2nQjRCwlsr0Bqr1L1XUDScp9qdSQpuhNwDsw7soSokNhIZUN8kFtrtZ/Xfb3p3Ugyp+CzN5ysXKQiTiRK1PcW70SJ1khhUPYeIMEjqETYN7CeNy/fyG876zEeaV3N/fgumDMMx1XJdBunUkTMSdflJaw5PChU3r7l1YqcBrHqhjPQkS/UWbu7tRkQtJs0Y5b50jqtd5TUJQ9B2Riiv9dcqJJG0HYVWKSrtvlsyXejAMVHlw9nlBL6gNVxETQl2g+q3d3QsVoo1KI2/9w6v4+03GDQ1VRiTBo+mVtf7PhZ12T10tM6QBzCmq2vPmeqz5wY2t2S6aL5vD41ClZwrFIw6udTw+VR2JS9MXUhLQ5nJWoxEokbgKm3CWwrddLjqCx5LrSLhB4iIzv3pLkYDk3SY6cwEOuVwCesIf1fE8ugLqsyMdrChfx9CCDb0qzi+bSh1EUeAFxZCtDeUaMbEFgElfNp9jabAIyHVVN+YXsZXM13ENZO1zSvYWssjpEput2NR9KuEB1ZamkvEgoCEZnPVyEa+3Z7DF5A24kyOpOvjYMBXTHipwKfXHauH4eY3T6Ufh6ju06/5nDQNAiROeK9r+57nq5muuk7n2zoWc3E0w7FwDj1qVYig4YQL9X8Z6OauMyCsf5S9gT3mugkhpgKLga1nvL0K6JNS/sECkzNLsq8ceoqrZYo90xZwU3Ru/UHFP/5Wpvo6puUTafC4tzXH3Mg42UDn8dQq3J/8gJaWEnqIXtg7/DKPnxE3m3Od4PttOd5TEbx36XF0M8APNG7L5FjmRfhKtqve9huZnEJzRJOsaZvHZBHhro4cpukzO/SCE1JjykUjZKRB1LDpe8sM1ooxjo338UhhO0cXzuE3WoJPZ1dyd3uOo0T5RPYK4gEsv2qAxSd30ChPxy+fFUW+kcmx4AuK6OW+8Kg298Xn+XB2OUcWzGGWAzttk2NDTRycPY9t7UuwUMnKazKXognJI82raRQmhy6ay8rBrWgRFQdfdvUAU5xATUQrQk8wxG1vGuYT2St4l9/IpoH9PJ5ahUDS/44ZPNCi+uP2TI4AwcezV9Dk+6xtXsE/3Pg8ANGYS/e97+aWTBdOzWBGUOEnEbVYyUBSHdTZkF7GrNg4sbjDx6ad4IM7YtRQx9y1DyWx0oKqBpc1DhKMqUltSUn/22awrX0JA++ayaaXMkyeM0YinBg/yWeIIEgFHi1YvMmJEG+skZEmK1rnMKgF6AnVt3/rWVhaQBKD3PBm/rk1h4hGFPJA+PzInqjzhjxWbeaG7CqyruTkipn0v20GkQCeSK3kC33dfCXbRU0onO5vUyu5zSzhexr/cE2FD799gCXpmczWVGL6e04SO+rSgM6/l9Mc3J/m7pBH4ripKgTjwqNTr/BvT3VQ1gRro4IFRjNfyXZhSRgOalySnkGbNOhqv5invCZiwiCrx3igpYvdQ6rI59rMMn5uRPmcp8SEZxiNzNi7lwfdFG2Bzu8iFos8i8ZAedZDQm0etukRk4KP1uJcObyJSWYTJw3Jb4tpYlKwZ/hY3UkoFZWc1BO9O7k/3cUCt4YLzBBxtg8eIqGrzeN62cHXMl1sjejMtdso+CW1iQqNmzR1mkhLnXuDE/yln+YCLV7P00z1BA1+wPHLZrFUNNIkLFqkomtNC4sGqfG8eVpv81RC/o+2N3ryTwiRQIUsbpTyLH2c63gVb/nMkuy9007HHNdq4xRDVYvqg0/WIWsA+0yfZ0N2tZU3J7E+8XmqZQVTO+Utn7LHU6s4/ks1KAqGSdtvDrPhpJJruqXQzV+dIRn0UEsXaxwVy7s7dinr+vfw5YUqrDDrwB4OGqe94Jf2Ntc90PanDvPn7ulk2oXP7eedKG7mRV6F2XqRj4fH3INrG86KPwOsCpSntPtbo9yf7uIbngoD7J0+nyZOxxO7giJzZyrWsMv6tnOJZ/P5UFoqkKLOLjdz3152ZC/h9p0qTtny4H4GjNOPeKXWzN/9XkGSnjRKfC67iv9LV7/z1p0ZvuafFjJv16rEQ3DS35tF/vo7i+ungg9/uruOYgD4aNXECxWzjYhPQ/Q0nOwXhzt5cKVKuv4ov5ErPzDOS1vVMyyVbLS20/JV67dOIhKymq2cnqej+zC94f1/rDOv8OuhXT94+vltGtjP5VWJ0akSaD+2dDx5+ncv0CZ4+u8V5tYQAbf4Zv3a+5r7uH9EJWgnbToEGswI+bzXNS/n4crhetslVw9ys6Oe2R2/auDB37Ty6GzlFGxML+Pj4nSS8z3RIS5aqJJ/96VzTHElfx8mJI8Fsbpk1bfzT7PdHagvhk/07mSGeTrB+FZzhKxQC9Na22FKQztXdai8x3udWh1RAyo+/hdRVW14aVVy0pBM9dWzWOQa/IVzmld6t326f1ZUfN6TPU0CeWZS+uFmxdMxz1JTOxWcVtEB6Eik+HiITJrjqITxu1BjbKqV4sfhGAf470ErP9LUOH7EeRlQwsYAj780iYOcpvRccHwXl4Vj6nJtvF4+/7rZGzWUASCEMFGL8gNSyn8/430DpYz9s/P5nCNjDRzRPWQg+GXhWUb0s8nZA1+AkByTFRr8gJoAXA/p1fB9jYFylMsik3hbx2LePrKezmSaEU3n2HgDYxpEA8lDLV2880MVYkmHaY0ZPpVdqWKTs+cxpCvIzq8Kz7LVVoPuu7smMxR64qeOgbcWetA1lbA7RSh+3VAPV7YrPoaRTy2mbdIE38tvYPXQFuJxh7JjkjdVokwIJeH+29RKvt+W44a+bv6u0I0faJw0RD3GHE0oOkU76TFkCHRNEviCcsni6o5F3O0e4p+e7iCCTiJeoyTd+v0IoSb71wo9PJZaRYCqPJvdMJnnmKBDGuz1hvl5YRvfya9n5+CLxE2Xe/LrOTyaJ5to5iuFbsq+QSSUT3qqbzdoGo8UtiMDGAtqLG2dRTxZ45iI4CJYcHwXsuJgNqkqRc/XqJRNbAlBOaBF6iq0FASM1SwCYKRmIytV/HHJsC5ISo/fuimEpdG57SC7Oxexx3Bxq6dijmAKVSx0R0cOz9HpF2ohP27qpL6n0BX/kt9ETSqlm0MXzaXgxJgIK+BGA5PlA9vqzHq+pzE13s51IbLl2LNNjPsmEeEzIQ3KXpUXRUhTFcCbRzYpvgt8pADdUtWpoISBfVdjuzdUR4x8ObuGYR10Kbm23E9ueDOJwFfc3l7Ab1MrKYWbd14PWN46hy2ll5S0GoJyzSQvq9yf38KP85tothK8UFQojdaWInNSnSQCyAcVvJqG72m8qDm4QnB7voe9po2PoNdQIg411+DLvd0MCp8nUivpookjlkF53EKi1LpPxYilhGFdY0flBPlKnLLUqQjqYbNJeoI2u4mbsquRwIuW4N78Rj7b102fcNlRUvd5XEaJBTCMSSlw6JdVqoHaJI7pihXxk/3dbC0fY3s1z5gI+EYmR4/lsIcSrqdTkqp94vVCMr9RQxlhDPnHwD4p5T++4vKbgf1SynMrYJ5hF3cOMMM3sKMu78ksIRbAFUEMvcni2+05GtJVjBibJ/p+AAAgAElEQVQ8XHiGhFSK2tLzEYaNYQSk7Bo/zW9mtpbkro4cxycG8YSgzaoQkzBkCFXaHFXVaEfGCpTx+Vqmi8YLarR7Abs7F3Fl+3zuzq/n/nQXXy/00OqruPSFruCFqQu5LZOjqalCWyBYGJ/MBzKXcVdHjkbNZnZqMlpTgl0vtnNLposnU1cQTTi0NJRp9cC0fFraSpgS3jqygQ7P55sduXpmPnPGickJBWaFphRVdC0glg1ItZf5j95dHBg5wdcLPRx2h0mka/y6dwcacG9rDjty2iv6tH+AJl/SGAheLvczUyQQQLue4OPZK/hqpov5zVMRQi0gV3cs4k0Ns7gus4wmq0anp/FoKky2WBG6m5eTbKtxkd5EgxahVjFp8X322QYnLp+JnmnGaLaIxFyqrsFYOcI8v4LRZhOTAk1IRDJKe0OJv+rvZnLzOCIexWwzaPcCbBGowplA0veWGTieznLHINlRw0wGNPpgaz5FfMY1SbK9ioUif7rYrTH4/tm8P7OU6zLLeCqqMTUwKI5HiOORDHyEBpOjKnTyzY4c12WWkUjXcAKPx1JKlTkzdYy45uFLgYkkZkSYLm0iEqQTsK55OR2d40wPTOwAtJhC8MQjDoEvMCM+FxkpLNvDaNaY42gEQhVHXGin2dK2lAAQ8QhFXSMi/Hp4oi3QuNhs4f2JOXw8ewWG0GhpKVGVHu/PqHzJ8fIAQgiiQmd4JMZ1kelcP9hNTXpEUyHiwrNY3KLyLB2u2sgyHmxuvQzb9Ficnk5GGjToig7qhr5u4k0Of1foZsArcm9rjjVt88jMHGe+KDIz0s7sjiHiwuPGvm4eLGzl3ZlLFTWvDLgr/zRfL/SQc8t8KHs532rPcYlnMe6U6JVV5sZGudDxacGh3UiSERFWR9UJt9PXeCK1krs6lC7ldLuFQaVgyDUVxSTZ2FBBD5cq+/wpT17d3qgLM3AF8CHgyjPgcW8Pr13LeST9Tpmd8JnjONhxjwUkuNIaqSfi4gHEp4HeoG41obnMqPmIlhTSq9HcWSLVXObOjhwzPZ3VTPCZ7CquH+ymsbHKFMdnka+oFifWFoi3utyf7uIyP0LWF7Q/dZgG6fFSMckKTR3BZusKfN/pKr5nAcQba0x3JFbMo9VTvArLgzjzaw7LZJL/Ys8EQ+eakfXMduHCjhHshM/mUjOTPZdEm4MV90n5ksNz59Jpl5jmBMxyPFoaylw/2M3m1st4PLWKRGuVe9pyRKbZzBBl2i8cp7ArTqTZ54dtOW7NdPF4ahUfNDqJZJSA54XSZpZfRdclI59azC2ZLn7VMInpeokOT/LmxotYUwmY7MIiEkyRFl8v9HB/LEVLW5ELPY2ZWpKXvQnmEKWxsUo8gAbh8uXsGvA90skytaLObN9gvt6EHXWZ1jJCToQRLNtCa4xiJzw6p4wyfdYg7S1FRNRisitJNaujfue7VWwy3uQgbAstFWWKVSIVr3CxU0NvjaPFBEsKz3KxPY6eULwpF7oeba0TLHUt5tVAj8GSmkbWVeXc6V8cICFM5hPjw9oERSFJTyrS2TrO6r9tJJYNaMmUuD2TY4oTsETGMBsl8+x2/mRkPfNrYMQlq4e2kEkVmdo6yoGRE7T6ithIb42SbiphxhWN5hJrjJt2ppkXRHBcnXjaId7u8oP8BhrSVcYO6LT7LkscFcpZpDXSnpmgw1JH9rmiSKZ1nI9kl/PDthwzHJ9LPIu78k+zxLN4E80k2hyWiyYuIs5XM10Mlsf5J/NiLvVtOmeMMiYUjO3dpNFj0DypjCkhP5jk4eY1ZLQqCd0lGij+5SWFZ8lZk5jmSO4wXIqhfJceshS+3b6AZCBZ178HPSwZuEo2MTIcI5ue4OmWy7m3NccvC8/ShMme4WPcE6pi61rAVU5EVTt6PqPVElf6CVouUPOpJV7hy44Ky0wPLG7NdDHfrZK2q7R5Sv9yuWzgzyqCi2uS/bbOnzpxDCNgka7yMGn/3Bjz/5RJef7//jfYH4PK2CClFFLKBafgcVLKx8NrH5FS/uD/7Wf3Fs/NAvdKc4rnf7Rp+NPZ57x2UcfZTGAjH1twzrbNwfknBHKtfa/dKLRTyh9/yNpmnS0nv+IjzjnbPvBI03l/5x3++bPz/Tcncs5rkUnnP2EGnyq+dqPQyjXznNeC8ye0o7pu/2s3Cm3/jIvPu+23lr1SwOe0Nc48u6jlk68yFnr08y/C2Xrux/A/WTJ6bva7VxbWvJrF4+ceb6+0J1Irz3ntkcjZzzP3KgViOTlxzmt/tL2BPebXzWpFnf2WRa1ksNbvZ69l8d32HASSkgalI+AXVQcVA5PDto4cGkEYNsWRCCPDMW7u7eaQ4bMjSHJPfj33pXMMDMc5Zuns0mMs7d2OHC9SGjD50GAP2/QqeV3S99YZjAuDStFiU6AW5wN+gtQ/7+a4qXF47lwkUBqzedESOGWDI6ZJjYDNWonnbYvnRJmf1A6B5/Or1CoOmFDob6BW1KmWTY6YJuOFCE5JZ0QXzNi7l+O1OC9ZGgctg6HxWB2R8faR9RQHInymv5vqkRqHZYy+ow3oMUF1WOeT/Urep+lbW3nAO061IHm0dJCjosZBPYLvCz7bp5Jz14yf5EU/Tq8h+N3YPtZFNY6akl0UOSYcvprpYk+tj6H+BEeNgEPBBBcYSfZTYXw8Qi3kJb4jvw50g0/WNOyEzwHd43l/lFrF5MhQim7ZQPWkhJpDMFahVjQ4fqyJFw+m6RtKICsOJ0zByLBywSolNTkrYyayUiMYqXDMiTNRsXnBsvEHSgRlyfbMpRwhil8E6cFR06B/IMk+02efpfIy2+2AfIhDH3z/bIrS5XnK/GuQJCEFgycTHB9oYNumDOW8xlAhzlcK3RyzNLaLMu6YYE+tj0dTq3neBq8k6B9J0Dea4KUBtcEN6HDANnCOlhgcjeOWNI4Zku1OI9KT7NGqWKZPadCi1GfyuewqxgdVLXSfbrLdUivpp/ui9BWS9DtRpOezVyYoDDTw0/xmft73DIctnR2Gw03Z1Ww3HH7PMKUBi92U2EeJrxd6SMca+GZ+Hc/qNU6+2Eij1LhqZCO/ZBC/DMMnY7gCsukJ3ju8joOlRoq+SUUTbG69jB3ZS+h2TnLAUnDSY6LK6qEt+K5aCh6vvcyILljTNg8/3CueFKNYtkd+MMnqoS18fKCbd2cuZRSXec1T+EyYyIxYHr82y+y3THoNnaZInLV6kaGXVQJwqBTlQKAW2xc1h68Veri7PcdgLUK/oci4NotxfhaVvGALCk6Mf7dKeJ7GLn+Udc3LGdRfJw/2dURlCCGuFkIcEEIcFkJ8+Q9cvyAsxtsphNh9RmThnPb/iYVZ0yUNPpQmbC40GmnxJY2+JCiqmJZT1hGaEvOsCI1GH9bf7SCdCnbUJR6v8YnsFewPxpnu1vhidjWzRInmxjI39HWT9iQb08sQtlXn8C1JTyXzEhrHLI0Fx3dxlUgD8KHBHm7NdPGFvm6smMeoDpbtcUuhGykVC5crA35e2MZNvd3MI8Y10eng+1wzsp7bCj2sHtqCnfQQmiTr+QghGR2M4aOKQt4z/DQecGNfN+mm0lkog1iTw19mV2ClNSYHNZrSZSoFRWb+zY4ct2S6+ElrjkutdnRbsiw2hQukxccHuhkZO12y/mhyMhqKqe+ixGRmuRptvuDhwjPUCDgqqlwRmUxTqkynp1GVHoNBjQcLW9G1gD2Gx3uGQ9xotcxzZoTSkEVK6vy+bzeG4Sv4lyuJdGrg+whTJ9LgkukYJxmpMeeyQaTjUxaSiOUhNI1o3OWhlq66irR0Akwpqfg6k90AYWhIDxoaqkQDiV8TBA58pr+bhniVpNS4rdCDU9RxkNzU281eI0L6FwcYDmq0C5s/qXqMCIkdUcrhLUYNt6JjRzx2TV7MFCfgwcJWfEdwZUTFO2/P9/DiwTTVQOfK4U00msrbdFH0qdaUGIYWUByx6QgEad/HG5fMCyIsOrETTZeYEZ+FrsG8I7sJqsqZmBLGpps1m2SixpSGcYShk/J9rBCz+472xXS6EguNBqkxz7fo1OIUx23mEKNV2Hw4u5w5iUl8LruKKBrtkycYEj43ZVeT0eNIXxBvVPd8ZKCJr2a6MKUkqnkYIVb5kvwOVllZOnzB5f3PkMXmsdQq7Aafb7XnWGC3Y0po1+MErqDiGaQ1m3xfI7nhzTyeWsUtmS72VHpJYjDXbuMbmRxfzq6h6hg0C4sv9HVz3JDMTXaykAR+oDGq60xIgylanCoBDkqVOwAkgpt6u/lydg0NwuLPKgJbCoqaxi8Kz6AJiRMmHE9VBf/R9jp5zEIIHbgHeBswF7hOCDH3Fc1uAX4upVyMCvN+77Vu749J/kWEENuEEM+FJdm3hu8LIcR/E0IcFELsE0Lc8Fqf5ZQNahoYRoArA46YMBiC/D+UvZxEm0PgqIkzomuM6LD6lmaEFa1nv/tllTlaAwXd4ris0O9FcGoGd3XkqAnBuG9y7J/7cKs6X86uqf/woBowo+azrnk5ezXF6vZgSxeVsPqpOmFiAAf7FYSpUjaRQEW6fCh7Od9tz9EvPAIkjd/cVP9NOyddQmnQJt5Yw0UgpUAIxSUtQyxzNfyO0fFoXdUYwKtp/Di/Cb8ckBveTHncxnM0hJAMaQG3FXqULD0agauIXg6KKg+2dGHqPl8Kpa3KNZNRXZAMlBz9CUMyoSkgP8D9+S1c7zqMjUYZ0eFkbYRhv8ztmRwDlRitYfn4W9oXgGnR7kl6B5O8GMKaymULS/dxBfjjPpgmQc1j8pZDlMZsYjGHgQMxpCepCai5BrJSozhuo0mp4pquS1ANOGrpVNHxhKDlZ/vrIzMufTRT1jX/XmmHAqU0PtUNK+ZKJ+iTNQQSHbCjHul4mVHPQkoolSwcV+dIKOYqNDguy7xrRG1AqXiF52yL36VWYBk+i1qmkZCKRTAoOTjB/0Pem0dJVpXp3r+9zxRTRmbkHJGZNU9AzQUUNWfiPGHzqd1yUa+2V1svSDtcWppl60VpGptF61X5bLWvrXK50E44o9KSNUAVc0EVVdRcWVNEjhEZc8SZ9v3jRGVWoonY8H3dy/uuFWudE2fHiTPss8+73/d9nkfi2kF1Ql1Irj0U5sbhwSmYuVKCkgxKHv0aU0jSbdk93D+2l0tO7ONUISixPGZq6JrP2vZFZNwiuyyPYVXjM5ntHNVchrwSrieZFB69yuA76T08PPo8p1SFnHKo5g0mcVnmaBgIfFfg1jWGdJ+odKdQplsnHuWsAbYfqJN/Kb2LSmN8O1/6VhwOBtRhv0JOAw+FXdaoKh1XKUzN418TGylIjZzwMKXOJA4Zr8TfZAZJ+JJzboQocgqQVfLrFIUfJEKVIoLHmKojEbTSqGwhgIzfnOrnoCpxyi2QlYHO5rUT27mje4BazWDMKbItu+e3iPb/zfbKxZgvB44ppU4opWzgPuCtL/w3/kCB6pfjMdeBK5VSq4DVwOuFEFcA7wX6gGVKqYsaB/qiZoQ85jgOy4ee5bHKaa7WJ1lou8i4wWY3jNGpYXTq3NU5wFtWnwmSKVKi3Drx9hqxRJ1NKk6Pr5H0bHzgrbmdzH9/KxfVXdo8l6h0ae2pEO1ySPiSfi/Gt9oHkKYkIW3KSuc76T2sq/nM18pYSvCzxBaWHD5Ap+Pz5twu7ugeIBav0+oF3LHL/TCL7aC07c70TvI3b+XXiU3c09bPmnNPY0ZcfnUuRatyiLXXae0u0+v4U0mwA1T4WWILm8Yf42K7zhy/xo8TW9EMny92DWB0B0mySLxOOW/RsqDOosaUs9P16VQ6obkaezou5570o7T6Lh3dJW6+qhCASkI2K/wKvY7PHK2JlXXFh66t8sDwXlb4IW5NDtAcr9LcUqXXgTXhHhYZCWI+dISna3kfHNkHhsmKphyJWJV7G3zB0ZhNd6rAYlnGLQG+j9YW5dzGxbT2lIknA+rPLz+cpMcVxOM1RDzK/HfFCCmfSJuDiEUxFzbT5/j0Rkus7x1m8oZL0SIC3fKIaw5muyQyN+gr8fYaC5xgVAm1emwWCVq8oB3A+qYFrFIRYqbDEpsGR7HHppsTNM+z6eguUXam45xWm88amvhK1wB3t/fTs7HG5XaN3rYC8ZYaz0ycQFfwF6ODaKkWHrFCtPaU6XQDGPqWRsJ44fwJQs0ORkODsamtTuGsxQ9at9EpAi+24tQ5vvwiukMVmj//CBvcCvF4jVVmJzeoFKsdnde7MT6XHGC1o9Mhw/QsybPE06eqEa7sWsFPMk+xVkWIJ2tE0OhxXVZ7IcyEH/RXX6IJxeeSA7QIh4daN7Ky5pJsLXL5yJN8NLWV1kb4u4pPT6RMtN3m7vZ+WkWIiA9vcmOE2106QxWWEcbxJc2WTcT3uMjTebs1n9V+mEV6C/e09bPQ9lkczZNQAdPhyjpstnpoVpK2+RUiyieZKPHhmsFyz6DT19hY17jCL7PAKrHIEfwk8xQr9VbivsfSeuBRt3kQbapzKHeGnW1X8M2O///5mC8EwzU+F4p/9AAXskydhd9ifPrvwLuEEGeBXwAf+X2H93KSf0opdT6LYzQ+ikCM9bNKBZXZSqnRP3Tfz1ZnT17lTs7MfDi12U9h+N6ZyZamqxbP0hIWtM2UkvrL14/P2jb2IjpgL2RZu0zPz9r2vTVrxvr9IX2WltC1vDxj/VXvml7/F2PmNbnvh7Nfv5Y7H52xfvHx/bO2XWzP9Bb+sjq79yBnP3Q+9raZSZyJX8wuizX/2ZlJuoI3e/KPF8wyC7e9Ydame26bXSqs/oLZcXf77Emnq8Mzk8QfuWJ256dt7cx+ciETXf7mrTO2PWTOnlw7X09/3q57EfRbestM2an4iyT/XszO09met/aW8iwtf3sQ+cWLsNa9Ord7xvqLJbyvMWa/Zy/b/oCB+UIwXOPz9T/w364BvqWU6gXeCNwtxIsLGL5cgInWYI8bBR5USj0GLAT+rPFmeUAIMfto2LD5zx5iT0jn4MIVnMhnePf4ds4YOt6kzV+MDnJiZxPepMsh3WXZsed43AwR/9j9CCuKU9PJDkeZkD43Dg/yrGVRVPYUK9w3QlUyus6YssBXuGXBJ4cHGdJ93js+SPv9Rzgmw1Nc0PtDGkNelP/xy3aOmsFok9Mln0n2c+PwINmJCOMywPzvk1Vel3t4+kFxgjjYtRPbeah1I3ZFZ7waZki3qOQM5jx5hOctyWQuzM8SW3hjbhdvzgXkTU9ZFl9K7+I7oSr1ss6/+Bn8QuAFPnu2k9qIJHs0xOGGN/0/v9vEfspMPK1xRlX5UGozr8s9zJmzLZzSfY5QZfXZvTwvIkxqkrJyCSufr3UOcHv3ADcOD3JM1HhN10pGx5rYZ3qccvMUlcMpzcP1JPssOCusAGnm2Py1HaNaM7ghtYXPp3eQHm/iwOkOvquHKY2a4HnYRydx65Jq3mB8KIZd0XFHSjyp1zk3HkdV60yMxihKjUImhCqVqR3Ic8KU7LFb+ErXALUDk1Qzgky6mXO6QX3UpzwUMA1mzsR5soEOrBc0PpUZnNKIrPzmKP86cYCbhgdxPcl2y2H+s4coFEO0hao882gX1ZLBQHYPdaG4JrmeclrnqCpz/cggpwzBg//azfGxBE/l2hkebWJ9x1ImZMDQd929MDIZo5y18ASccyK03x+gJfef6KSWNyiPm5zWPCbSUbxJl+ctOSWa8JnTHUyMRZmoBWyIm8cfYywbZb89xlmvxIQGX/ROkHQDTvL7Mo8xfCxOQfh8YniQRS0pHhrZzyQOh2Sd7Jkok8rhjKGzW5Zx8oKJ01FKQrFp/DGGhUu5bnBCs/he2GFHoYM9HZdz0M+zz/R4uH09e+vDPOo041Q03j2+nQm/SkM4h8JZi3Qtwmcy20lnm/B8wRlD54jm8hxlPjE8yI7ySa6Z2M5+S3C03MyocDll6LxzYjuHvQLDwiX9fJxhXePAZIK17Yt4TKvygD86RVd7qh7jfi1wYE6pChOaxnOW4Id2gp/qRc6OBEjRrROPMmhMowNfjinPe8mf32PnCCIE56238d2F9n7guwBKqT1ACGh/sZ2+XGkpr8Ei1wtcLoRYDlhATSl1KfAN4Ju/67cXTg/+KtrBZzPbyRfCbOhYxq3JAa4bHcQrKD6U2oyUivqExCeQY8pJn/yn+lHVIiMTMfKVELend9DX1E7CC9R2nyy1kh5vYh1NFLSAXc4fmWByOMLru1eTx52KxZYk/DoR6OblhY+lfG7JbGdE89nbs5ZRDfrrdT6U2oyvBAcs2DF+EKch135XeheXti+eEWOuK0m5ZCEJFJZLhRDP9K5hUnhM1MK8ObdriikrWwthqYDv+AeZJygVQvTqTdRHg4G0U9apl3UcR2OSQGliWPoUlYMVc/lB5olGtA5cJTlDnRouP2jdxqQGBw2P+4ef5Jdh2Ke7bCfwRI67eR4c2UfZC/QNJ5wiP8k8xZ3pnZxzItyW3o4jBIcrw1Au8OrcbnwlOOJPe5Q+AflOqMnFPZtFuZAdjlLMhyhWLQ5k2/BLHs3o1JXEHy+Sr5sUNMHweBP+WAHlBwToLZ7i+pFBpAmuLdk0/hh5DWp5g3pJJyd8Rp3QlKNcKxq8tnsVN4wMckaF6f7NMRzf4+rkpZzwI4SQPNO7hnEnxD43TjJeIp1t4seJrTgEOnnlvMWu4jFuSfYzKlw2zMvgAk2+h+dLTlVHyQqXqvD54mUTXJndTbVicJ+WZVzTOLVuKW/pXouJT3Y8ysRElDqK1Wf34uQFDoovdQ3w1c4B/md6N2XHIKMZ+MM5vtjgU/FRPDiyj7pQzDNb+SYZbkhtoaepDSEUh/wi2zovodOI0xVtwVYeNj61us4xJ0taU/w336eSM6nbOqeFzY8TW4kh2aNHqEmYq0L0OS62p+EqHwPB5vHHSBrNfHh0kOJEiI+mtnLazjIkA4cgm4swouu8tnsVRaFzxegTeALKeOT8Gq/tXkWkwZdxS2Y747qkiEdJBoCl58tn8YCqbbBbr6IBcS1EXjkktBDvTl3B7d0DeIDTuKue8jmnCyaFx1Ib2oWFpwQrWufx/dZt3J2eOeP7N9srVy73BLBYCDFfCGESJPd+8oI2p4FXAQghLiIYmGefNvIKVWUopSaBQeD1BDGW8/Ds+4HfWRB84fTg78tj3N3eT3t7ieVGG5fUPT6Y2oSRMvjH9MP0rcwT7oFupbPUqbO2BnJuH2g6fb2TtMUrfCrZz5niOHPcIB713vFBUu1FulxYYHssEWUmd+ZJpAL0XI8yWGkHc9g+xyPVHERlFriSbi0okJ3rSjrnFulzoLOlzDLPoDVR4SIbXtexku9mHmelrXFrcoCtZnLG+b0h9zCxeI1X53bT7Sg65xUIRxy2VqE3EQAyFrka97T1M6ctzwLbZc/YIT6e2kr3ogLzRASrW7LYrdPRVqIpZdM+r8wS32Sf4bKuLlggY4Q7G0x0fsCr3B6t8OVXFVhDE9u2ZVhS9/iH9E7Wty+lQ+ks9nTe7iW4OdXPJr2DvT1r6UkUuaetn2OT6SmSmA5Z5ytdA3R6LttiCyAaDyoLEhUWyKD8qa87T1+kzCV1l3APGMv60DsNYvEaLe0V5izIsaJjHL3TYqWj0RsvIjvjrHtHmaVuna7WIrIjjtkdML4tCwXXxUiGifW4HFq0nOV1h/hCl3iqzrq64OLkBHP8IN8Q66ixQgbeVJcKpuxzmzq5jCYWyApLPZ2Wjgpz4wX+fGyQ1t4yC/qydOo1kp7g9V4THYvLvDu+MijdSu8i3OkRwidpVZk3P0sq1MbFnsFFjobeEWZvz1raUmW+0uzS6zrcmG7mp8NPs7AnS0eySO+CSe5qQLRDfRrzHUHK8bnYrfHJ1DZ6u/IsFWVkZwtdrmJ1NMczE8f5StcAi2zYJFpYY3TQ5+u8L7aC1u4yW2lhx+gBdo8dYqQ8yYH6CJf4Ydq7S2wwu1ld9/mhFqWpu05XX5ErHIv5sQLLbcE6u07S8ZnrClLREtuye1ikxbk9vYNnetfwfjvOI+3raemusNLRuDjUzTrH4MquFSzcMMlCr84q2UJUeeztWUvEh1WexWotQZ+MTg3M97b1s8yt0YzOURnQpK6KzaXP15m3dIIBJ8yCcJHVWisbVZw+EWG9F6bPUSyJFHi308J7Uhvok1HmOYpupfOo5bPaNenrKLDE6uDt2R1TOpwv214hrgyllAtcD/yKgGHzu0qpA0KIzwohrmo0+wTwgYZA9b3Ae5V68aziy6nK6BBCtDSWw8BrgEPAj4DzV28bcOR372Ha3pG8jCdMj2I+xELfxEMwR5m4o8Gbe/RQlOIJSVUoOmMVJnSJf+Ys1Vv/ntKkxUQhwnGqvKprJUO6xbJEH6/tXkXHJshqMKFpdHYVKWZDlMYtvtI1QJsveLxBr7luwTDftJt5U/caShJu0YJ435Duo4UVhlKMT0Y5qrmYEZchQ3DazvGm7jV8Qw7zFEUG7XMcvejiKYj1A4nNbB/v4j2pDVw7sZ3wApPvFjvYExaczcW5q3OAr7gnOGUKRrJNrF44wl2dAyx0NXJnw4xgUzunGNIs7s93svfpbnJnwxyXDsf9EodNeN6bZO+j3Xy3dRtD0iWta3zLi1M9YfM8VZysT6hRljRi5/mZm+bdV2YYNKo8YJ/haX+SNeee5lSumWsntvO55ACDtSCPMeFZPKnVqArJw+UhrvvwTrZl9zA2EePzd23gM8l+0iNxzlSivDG3i7NPRPEy4/gFl+eH28iORTk31Ew8Vaf12wc4YHiMFKK03PkotcNlTmgWI9km3KEJ3KzLgZBGR1+RvT1rcSdq1Cck8WSNotAoHNe5+/k+fm7VGMq08Kgoct3oID2PHGMMh08l+9lpWWS2LeJw7iw3ZwYpuzpnNJ+xTBOPVlqZ/MQVTGYijI/E2DD2OGd0n19rJa5/LsEPyke4LTnAjQ5YkWgAACAASURBVKlteBXYa5lk6yG+lOnirUYvhzWXc7pi+w9b+NPyCPnRMN8otnP568fZWw1mrVuGRrhlpI3R0wGR0g2pLTz3YIIzRiCGui27hx9WjrH4+YNMuBZ3fFujoAkK5RC+UpzVfE6Ygv1UuCu9i6PS5tbMdr53toenRBDfPU+zeTB7mqOyzl8NN/Pl9C6OmBrD2LzlgODjZ5o5ZHicLMU5YcAJzSJjSB416tziaexo3UBO2Xy7fYDVZ/fydXOS3XqEH57s5c/HBhnzypzSFQOynTNPNHFGWjzj5Xht7hHWnHs60L8EnnDHcVA8MXYkgLdPbOeQHuKAN8l+Z4JPJ/vJehU2OlWGDrexz/D4a89nqatxXNoc9YtcPzLIqC44XomzZX6a+cqigscpQ3ClV2IMm2d1m+HxJn6QeYL72vpnkJq9LPPVS//8HlNK/UIptUQptVAp9beN7z6tlPpJY/mgUmpTQ6B6tVLq179vny/HY04Cg0KIfQTu/INKqZ8BtwNvE0LsB/4O+C+/b0c3y+k4zs/9EfZdICf0zgvIjM5Q4+nqNBtZ+K8/TrU2nRz6zci+qeWrVCvP/3QaQfh4pou+twexvetHBtkpp5MZPz/dw1tr0xwTf243c/rSQHtt9EiMk+b08Zw+nZjB3ft20T21vPj5g2xkepq/PpTjXY0yr/QugzcwTb533eggB7KnptbnPHmEO+tB4qtQDPGdC2R1tnplls2ZTkb+fHgv1zWSTkvmjPOnDZ5kgD91q/Q8Ms2IdsyYvj4DRje37eicWv/18LMsbplOIN9bPz61LFAzpH3u+sKlLGoJWOuuu+7hKRIgCKTAuhZOn3dfZPradg8eY+yt02mG7Lsv5sC+6WPQuqbZxx4+2sP31DRbX2rXMXINRrarW0d+axp7IUKv2xOEVwTe87WpK6hcQHbT5br89NvTCdILkWmfNm0U0zfUqwsub0CoX1f1+Grx2altm9anOTo5HT6896Ekv1kU9LEfRhZyg5iGIv4XrcjCJdP37KudA3zHCK51UWp8/ILk8mUdS9jh/G5U4EavzFl3ut+kYq1TpFk3Kn+GaMJ9ncaMZ8khIPACmK8s7s88ObXtKXMmcOJV0emkZlX4U7qVAC3SmiFDdUCbmai8UIevTYb5MxnMHj3l87+s6fvwF3ac+5iuBbiyawVjjVr229Od/O/qNEPw/6vr9DvhqfUXk0D7N9kfK/JPKbVPKbWmAclerpT6bOP7SaXUm5RSK5RSG5RSz/6+fTU113hVVRBrqrNR72BDzWVZ3cfoDbHRj9B1cZn4csHd6Ufp9ALFX9GWAClpaali6S73Zh7jzu4BFns1us1mltl1ursLLLR95rl15skKsiVOrKPGx1NbWUmUjXWN8XcsZbUq095SZqGMsbTuNojjk2yq+qw88wxL6j6prjx9vk5nokS7Cy16hDWimfm2x2U0sdFMkb9xI6bhcVfnAF3hCs2dVeZ25PlFYgvhmE17d4kVdcG8jkkgeFjn2or2ljK/SGxheSRFi6dI9hUCdeGkYImqMGdxDjPmkuitcrFncFNqGz95uIfVWoJItxuUFSmNbtfnitEnuCm1jctUhPGhKIsch7U1RbMRoc+V3JneyQYvzKvNXj6XHOAtkYXMaw2O52D2NAOhPj6S2sLCRJ672/t5W3YHJ/IZMEy+H+si0Vwhhcn7UxuZMyfHkrYcr7JrCAmyKYzWYhCJ2rR1lkn2Fdg/dxUdPz7K+prg1bndaKkEczrz9LkOc/pyiLYWjN4QV9TrzNPKbKx66F0RzETwQPS4Lk1zHWLJQL5qXnKS13uBV9rcU+MSP8SmmsvlRp6WrzzF+1MbWe2H6TRqzHElyXl55sWKLJZl2hdWMA2PIcOgz5UsEhHa55VZFOok5QRhLD2qSLYWiWkOraEab4lfzBpHZ4kNxtwmnk6tpaW7Qp8nWWbXCScVn0htJRax6egr0rOiEAA1zjxDqEewyFb0OS6XeFW+bZgcXrKchXoJGbWY79hsGn+M5UY7e8YO0ecwVYp4uWPyvtRGkr15rtKS9HctZ63ZycJIN1tkG/OURXtXiXVWkk8OD9KBSazLpnNukUWuRlw43JrZTkrVWeHU6HXguXmr2JbdQ1KEuMTVObBgJVtFK1v8Ei3JoDxSFxrLnGAwbU+VuFgvsk7FmJ/Ic2TpJXS6Ht9IP8IcPU4T+lTN8jc7BrjEr7Dej9Dr+Cx0BCkjztfTj5DqybPG1pgbKnGp3kZSGaySzbxWtPNGu8rCSIFNdZ2jk+fowmSOo+h3QnxgbJClvklPd55rjbm8c2I73/h3KJf797D/EMi/WsXgmZAkm4vw+fQOjpoGw4bEG6/znGZTOqdjnw082jfmdrE7rEG9oeQ7ESCL/mtqMz9X42SExfaR58gLg+HhOG/P7uCcZjHkR1CFEvnhMA6KA1QoaIL27x1myI9wyYl9fCm9i+OmTh6dQ6rEc43ytcOW5MRwK0dlnUIxREUGsjm3ZrZzyNJ4nALPe5M037Gb1Wf3ck5XrE0/TXnSZHi8if2WjudIsiNRRnXBWDbKP3UMMKwpDlhBpv+kofNY4TjXTmxnIhPlgKzilXw2jz/GxJko1ZxJ/lyIG0YGedzLMqQrfl49gVsM6B1PihpDpuTRzsuYxONBcqw49SxHTYMjlmTv+HGO6gFZ+sOywlEVAAN+Xj3BWC7GZ5L9NJlhvpTexZfTuxiZjLHLDK75ho5l4NicrDSRL4Q5rMoMeSUyZ5uZmIwypiyqWR1Vc/BLLsqH0qTFqaEE48UAifh0KIAA+2MFTo4meF3uYSZGo6hsAft0jed1i5NelDmxIomvP4udC7rmfkvHyQlKGZOiFIyPRxnWgoRaIRPicVHiDbmHOV5tYuR1i7h37CmGpMtBFeMZ3SYz1Mx4OcJZN0LhrEko5PDh0UHO6Yqz1MmfC5F28rx3fJBTuk92KMxItikAkniSXxQPcdjwOW0IvIkK+ZpFYSxEQcKINKlmBOdUnXwpRPZclMJpkye1oHLAnfQ5ZgpyUmPSN9jnjJPPhzjXUG55be4R7mvrZ789RsSweMb0eH9qI3v9SZ41XHKqTjEb4ox02T7yHF9PP8JzxdM87GcZEy6lSYtjbvBSPaxKVLM6+ZEQB3WXgewePp7ayllpcVQLcdaAdD7GI+3r+dfaKY7oHpOFMIaCESc8BZs+Uk5zxAg88WI2xCk7yglpUyxZnB1r5q25nVydvJS9tTSjqsY/pHdyc6qfZwyX50WEvVqNU6bkP48PkvOqXJu6gsnxCOM6jFUjPONNkhEOu90xTkuH7UaE1Wf3csyEjR3LOKxKnDYEpxpCnGnpkctGprzy/cYrRFzveS/98+9g/yEG5uVDz1IVCikC4c8bRga5fmQQ5SocFG5dm0J+fSbZT7cnpt5m7S1lNOlTJ9DDq0hBV7QFS/komIr5+sCJ/11DCkURFykEfzE6yLlNi5jUBLck+/l0sp9hzaciJD/KPMXNmUH2z13FpPAICY8QGr4SnNEVyxJ9XJu6AgXUlMdDI9P1wEU8Bls34LlBbNER4DjBb8sSCp6JJ4JM9m3p7WgolIBPRwNEnq4FFRe+HXgilbrBkUwbQgbT9C4ZwUCwNNSF7wrekbyMivL4xHDA7fzfLxrml8PPMNi6AR8YF0HniilJBMmEX2XELbO+YymHcwEza1H4FO3q1JRxHIOvpx/hW+0D5BukCVdndyKEoqpcNCHQpM+EZ1KUgXiqqtbxa/5U6aEUiiwm41cvwUEFWf2izepLA5J/TSpU3UFIGNcCVOQ3vTgjr1sUcHAT0DzWCjpS95nQIOOGOUBlKtZYaUB160LgVWB+UzcWgmbPpw0dQ/dwlOQ1H/TxPUkm2zQlPuspRajJIaJZfC45wO3pHZRKFo+bIYpKp+QYzA11BNdQ+rR/7zBVpVOrGnwqM0hFCq44FIQkFAQc1CUTA8G+vtUc3NuJg2JUF5w2dXaPHaLm6kxoGqpi84WuAfKa4Mnxo7yn4zISSjLq16j7Ll9O7+JHmaeo1Q2O+8UpIYhctcQKrYVzqoYQcLB4hs8lgz7u1DRqVYMeX+eBxGZiSlKQgqIM+sBrc4/gKUFIBtzLHxeTPKDGeGtuJ1Y4uI5LoinafEnRrWIYHiUp+Xr6Ea4YfYIrs7u5o3uA+zNP0qxF+F7mCUK6ySlqtCmNqoTvpPfw98W93JLsRyK4pxF+ek7WqSPYKlsZV3V2jR7kqFfAIVDg8QkED7pEiA4P9lLkncn1eAS83XPjgZxaXL1SfMyvXIz5/wt7JRRMtAY5x88a698SQpy8gAp09cs/zNltYvKlM9HNeyFQ8gK7rPbS34wlXnrbX70I09YL7boLVFVeaEuSM4ENH7p8dqrr9x1oesn/+UrZiZXLXnLbA091/v5GDXsR3AqOPfMhDS2anXZtx9de8l+yzn7poIzdiztm3bZ02cyKqPMalL/L7svufcn/+ZPy71Rr+50WfpFx5e+8tpe8n8HWDS+57fXx2dVGPnNBbgKgImY/wI1+ZNZtL9v+mBVMGvaXBGUiF9qNF1CBPvP7dnBo0XJMJQiZLlU/CFHc0T2AcqETAyEVeji4QClPUBGg6jZoOtFQ0P58He+fjw0yVslPKS5XZKAnZyiFCAckRt9K76EPizu7B+h55FhAJq/Z7FUFYkpy7cR2rkttCWosPUmL0rB0Fwcfy/CY7+kcyp0hhMQAWoQ1pVz8UOtGEkrDkD6a7mMKj09lBjEtl1i0TlhBWLjEPMVXugLyl23ZPVg+vC15GXd1DmC7GlFhoPzgfKJhGyPsYUUdOjC50o3wjcd7sZXH5EgYH4iLgODI1D3myyiv7w7eh22uItHwMnwBdRRztBiLjBYuNtq4pHUuNRVwLbyqayUteoQbG1L0X+gawFCKqBYCGcjMS6GIC5O672LoPs3CpSphwb5DCFOn84FjgWpIIUY8XKe5oTwRV0GYRWsy0YUfsAc2TJjQ5wpKUvDF9E60uDbFD9zmqikFk5JQdGs15oowtyT7MUyPVTLOLcl++qjR+s/P0ayF+Yf0Tizl4zT6xOtyD5PTdKKtddqiVa7O7uS29HbuyzyG50haZIi/yQzyqWQ/qfl5LOnRLFxM6bN77BAGgh5PMvqmRUGNc3ONz3cP8IGxQXTL577MY0QaYZ9QxKGbQEkboUj4gmYf2l3FP2iCiOkQa3hhEQVL3BpXJdcxWSvjA7qQRKTJVcl1zG/uRtd8BIKLrC7+NHk5SxO9dJnNtAkTx9GYE+3kbzKDdAiLUJNDrKlOVagpiLqhFLaAeZ7GQ60bCRsu7XpAJHRldjfztCbua+vHa8xQDhTPYAAxLcTkZJiY7/O25GXYSuNXic1YKhAlbtaCuuctbcu4J/0oGoK5tsdNqW0k3WAAznkVPpTajFKwxrNoEgHhfwiNa1NXMF9rYokj0ZQiI4LjHVE1RjW4jDg3jAwypMpENJelkW5+0LqNvHiFQgt/zB6zEKIXeBPwTy9nP74S+ASdOq4FXk9RKIQJrb5EM3zsksZHU1sJ+UGHFlKCa6OUoOCYUxUE/9QxwJu71/JAYjMhwyXsw4gu8IVASEm9oQ5SQ3FGeoxfvYS6EBiax5CdpbsRwrorvYubhgdZfXYvTT5UXZ2vpx9BCIUB9DW1U1AOVQGaEDTL4LiHNIvPZrazefwx7LpOSPOm8P3Ljj3HedbCaye2oyno8oJb8IGxwQBcIiESsYmioYXg+63byJdD1Es6dkUnrWp82R/CB8q+Tayljq08/jm9myX1ALFXwmOOjAYESFJQEH5ARNQ4rxZ0asqjrFwWW+20WjU+n95B1isTlw11ZjzSWqB+EZch8Fw0fKRUtAsTXWgIoXCUIKfB8eUXoRqdePHzB+lJFKnUDdqjVeqjPiEVsJkhBYb0uX5kMGB+awojQwF4aJ5b567OAdysh1uXHFq0HFsImrpq6GZA3uQrQVxJNASa7nNYlWn2BWU/uK+G0PhAahMGCg8INRRdXr30DNW8Qc3WebzrUm5LDvCR1BacmsbxWuDZloQfECb5kprS8JSgPRJnr5+nJkCGJFfldlGvGow0qh+UHwgVrE0/TSjsUCpaTOCyf+4qUCJ4GQpwBDw4eZCaoxPzPTB14p5iEgNbeXRFW4gpQbuweLp4EgPJyXwQ8nlgeC8ePgVlU/McevUmDCRWyGF9o37eQ+E5klrFwEJg6h6jwiXsK+Y6iqxU1JRGxTb49fCzxBtVK5d6ITwCArGPprZycawXFzhVHqWto0xdBGyEpvB4Xe5hYn4QtjGQHPWL5LwGoZVQpI2gbG9CC0KOmpBU8DBNj4IERwVscTGh4yvF19OP8IGxQWLCY44y2dx5Eb0ijAZUheIHrdu4QsXRpc85exKJmpLxermmfP8lf/497OV6zF8E/orfYi3gbxu8o18QQli/43e/ZW2+wPcESRnhq50DtPsCGdFwBJgRj1C7RwRJ3PfodBVEwqDpeL6gOzZdnmUoGHPL2Eh0zccAEl7gOYz+bJJI3OZDqc10Ko0vpnfiFnxifjDgdBtx7At4E77RMcDhJcsJK+hKlLghtYWareMDF0V7iAuDqA8mko7GwPznY4Hn9XD7emLxOr4SxDwfqSme6V1DwoOQ5vH91m3UBXxsZJDHuy7lrs4BftC6jV5HYTZ0B4UZHHdLrEYkYRNudpgrwuybOImDYpHeghn16JZhrktt4a25nRi6RwSN5kYQIKQUcz3JgfJZOjzB7d0DtCmN72WeQEPw35yg3R3dA4SFQdar4KEwpU/Kk4SUjyEkhGOENY9w2MFE8puRfSglcJAsqfsIqZDxKONvW8Kxiy+mWLJItFTJlKNYnZKY35jKm0Hc9962fmpVo3GekhbPx0Ny3eggRrtOqNVj2bHniPo+Wgj0cICCjIZsCsIPNPF0n/szT6IDCaPOyGsWEZYGGgKBosfX8Pygiz93sBsz4mEaHkLAzZlBTASRFpsT+QyfSvbT42toERiSIRJmDU8JxisFXk0LnR4gBYOtG4glaix2NX6c2MqNZxLcm9/H412BUG28pcZC38S0PPSoIuIHhFMJzyNXLWHpHhoKpMBUiquzO6kpl4tivRgKvpF+hJHyJJerGH+SXIdpuXwitZVOESIhLE4VRlgoIoQajIVjDWBNFyZmzMUKu1Mv/znKIKJ8Yr5Hqy94Y24X27J7uDZ1BbXGbOJxrUaz7yE1xRfTO4lIky4XCvUgr9Dl23wktWVKqzLu+TQpiYuiTYYwhcYtyX46PcECxyGFxVnp0uELim6VFCbVmkHcD/Qa35G8jFYCetBbkwPc19aPqwSWgodHn0cg6HCh0xO0YjMpg1nqgewpakJyW/KVqsr4I/WYhRBvBkaVUk+9YNNfA8uAy4BW4JOz/H4Kkv29/JmAojHqMqlsFjgOw5pC1YIHULMUfg2kgks6JqgJAZUqOHXi8RrFasBVe1NqGy2ex56xQ3TqNea9w6QkYFQPiIeMkIfvCYZVlZPC5nPJAbp/E9T8HnDiDMi2KSXmD6Q2BVNV08MFcvkIX0rvImI5WCqoAS4rj2Y/EIj0UEz+5eV8rXMACXi+xK5r/JOpUZcCIRWmFbjjG8YeR0Pxj/Yxvt0+wOUjT2IqyGuSnB6wqjWjgw8hfLLFMPsPd1GZNNEI6j/jSnDWK+HZgtfXdCwEv0hswdQ9brlkmDTBA+sjyEmwNJMJqfjQ2wvcnBlkaaKXezOPBaKrlkNOKhx8mmSIEBJT8zimuXgICl4NPJe8Z6LrAZcuBFP6hFHnpCkp5UIox0FGdBYdPEgsYuPYGi26zat3utgCrhh9AmHozNscoCx1zYewhdADj1mgOLBgJcr2qWUDj65Jebhl0TgX8H2BJHiRaIbi3akruH5kkKqro8Ukvxx+hnal4yLJSI9QxGGwdQMbPtWG12Cl0zWfO7oHuDO9E7uis7nzIi6yA89Wi2uYSlF1DKSAFa3zqApI6yCk4MchA8+RfHh0kLoQ1HDZHF9MyQmujZCKg7JGvapz8KkOdAU5TfLm3C5e07USXfPxEHzth83YosGSJ3RWa61UJHw0tZVXda3ktHT5UeYp4u01PAKF8fNDxHfLR1CAFZquUMjj4dUlPyt0oAOXDT/JzZngGA0UCS9gCtzZdgVn3SJtSuM1XSu53AtRF5JiPsTt3QMYQuIKuDG1jVDcxUdwSlWoKY2Q8Jhs1JUrFJPKJiQNSkI16Ds1srgklMb1I4PEtBBpbOLxoL5bAm92YhTxKOKSEx5x3yOquZREcC8NghlYViq+ExKM4eD5grd0r+Waie3IV2qc/COuytgEXCWEGCKg9rxSCPG/lFKZBvNcHfhnAr7S37ILIdnvbO2dse2oOTuj2KHR1hnrtcrsbU9+15mxnnjt7LwhF2kzGcX+ds3sMkAv1jnWaYUZ69ep2RNJf6XPZAL7gndy9uObNzOR9L43TK9/05z5n589MBMefqG1fGXme/QOc3YmtQX+zNTbG3OzTyNbumaXRnrojTOTcocGZ2e/216amZCqvUgXlS9QszhPKPS77Jt/X5h1W+0FUmEL9dmlr97xgsTgXfNn3++yFTPv2ee16ev5obfP/N2LJfReWIewITp31rZvis38zxacWVrCZ7zwrNt+Y8/k4TkvGvC77I70jhnr7S9CZn+hIAQEqNzZ7JrqK0SK/7vsj7WOWSn110qpXqXUPALijoeUUu8SQiRhSkX7T4Dnft++ND1QR57/7CFSIkzIJ+DclXBbcoDzz82tme04QuIIQNPADCM1RVO4TgqTqJJECRrbXhADvWl4kJV1BwcBoWCA+FHmKdrQCSk4t3ExpvLxfMlRUcdqQNh//Hgfd7f3s/C559EJtNM+kdqK1NRUuKNPBPv7cnoXy/0wLf/jcTpSJUIIdOnjuUE4xUdghHwuPr6fo4bi6dRars7u5JSucEQwxTcV7M8OkXAVmqFIKIloIA7bmivolk84bhNXkmVaM9/5RQfrZStmk8/Ph/diErSVWuD5RgjgtxDE5E/mh9Fgaip4ebiXT6a2MVSfwPMkt6W306lFuVw0U8RDKUGk0ScNoYHv82RyHY6t4Z4nTLIlEcvh8gbA5Py07/CS5YRjNtHmIJSDLjHPj6Geh6V7uKIxsPrBtN4RAokirILQhhnzOHrRxYTxMJoVXj2471IqWn3JuAy80z5CfLVzgLA+PbieFnVCwiOmJEIqNKFY61bRjGDWYoUcbhwe5M7uAYywx5PjR8npgqgfyJj5SmBqHolwjbJXR1cQ8wEZlAAKqbg1GcyMNEsF6u1GkIRWvmCVHyIUCcoAPzA2SMp1+UliC2vTT7Pm3NNBKAMIKZ/9c1fxy+FnOJHPEPehUwV60Held/GO5GU4NYkC3pfaSK3Rt03Ok/wrbBWEhaJINFMhNUVJKH6R2MKd3QNkMclKPchdmA4xyyYsDY6KGpvHHwPgbdkdRGN1bhoe5Hh9nHENnh4/Rq2gUxYafSKCqXtsy+4h5qvgvBG0CJOoCBwjU0E7Nq3oU6WMz0ycYIkKnpGL7Tqa9LkmuZ46Pt9J78EjQCZ6SpDwBafdIhPYQbLUF+hC0YFB3dFJyuAlctPwzIH932x/rKGMF7F7GnDs/QTUdrf+vh8cybRxSg9GgbvSu5jQ4JjhY48rbs4MMpmJUC9oXJNcz2FLcsTwgymG8pkshajZOmlsnqDAcSMIaXsISrVAaPS0blCSASglPxHhQ6nNVAhoQnt2H+WwpXPOC7PSs5jQgwHuA2MBDSTAA1qB4VKUc6pOtWZwqDEI3JHewUTjhZ+VPrkPrmLuU4e5OTNI1dMoVSxGyxGOG4p6SeeJ7ks5JWpU7KAzWwgyejDFP+9JjOkCty45Kxy8guKgaTCRj1DOWpRyFsdFnRN+iZxUlIRPaSQ4xwN+ERcYK0T4evoRTvklTsoQZ4ygSB/gpKiTFz7vTK7n2fpIAOaZPEeuEjw8Px/eyy2Z7Xw5vYsx12K3XmVSkxT8IJRxrhZlshTiOSco3Utn4xSrAYDBcwSqWMUZtalWDAq5MJWiScRycNI19usODyQ2442VSdcjpHXBZCkEdRt3vM6DVp2i0DmnQ9u/HKI0ajE+HmNS6LhFQX40zA0jg2TK0WBQBiaHIzzr5/nw6CDjzrRXvqdymsO6xRMqT61sMKwsTogw2eEo2XyEsVyMD6Y24QClXNBfTmk+JzQXq8Uj51hsGHucoWqME/kMZ2RD4iztsk8EVLPHRI2TpqSa1Xlncj0/0mKUiha5bIRPDA8ykY1iN/gzzxg6FTntGU5KHWW7HDE1ssXpkrCTmsdJYQfCBMD3Mk9QKVgcU2V+XTxM2Q+8339O7yaHy+hIE2XlcNYQHPFLlCdMCoUQB6hwzNTJC8UxU/KQ5fCkXmesHuZIPc4vh58J1FDa15PWFHe39zORjfKR1BZGa5NTJWyurTGhadyV3kW6GpSlnjMEGeFSVS7fSe/hNxMHuCG1hRO6x5AMcVt6+4xn+6duOgjrmBYTnsW9mcd42g5mo19M7+SkKTlHiI+ODJLzKgy5BfIShjSPLAYVfE6rMI/Wf6/oxx9m/xeUy6GU2q6UenNj+coGHHu5UupdF5Dpz2qtRo0WX/JEd8DH8MnhQWJKopkELHOGh24FGm03ZwYJKwEhC/wAGWcaHk3o/CTzFEnHZU37Qq7M7sbSgwHJFiCV4tQ9RSJRGwOBR0BNCBD3g1jmx0YGsS64D8dEjSNLL6FPRAhJj7DQyNUtkkpnfUeguF0XsK3zkuAHvuK+tn6uS22hNRzE1Qzhs8ARuLak7mpcpMII4NvtAxwXdcrCn/JsP5Ps56BmY1d1nnLGUH7AjBc2XDQ9AEiE0HgNCSJKUMbDcyWv6VpJVBhcldtFkxUka349/Cwpz8ZQ0KI0FjQnma+soPpBhOjSm6Y4FxSCm1P9LGpJ8YbuNbw/tREDhY4k8trp9QAAIABJREFU7vm0a1HwXEpSkohXWWq0sqJ1HhqKsqcT9RXKF3j5OtIUGKaHJn18TzBZtZAhQa8yiAgPmQjTJFxSriJqOai6jZCCS/wQmlK8zi8yfvUSpKYIWw6OCF5U4ZjN7d0DNGkOk7jcnt5BKOLQJ4MBIy81Rl4ThIb6I/PocH1SMpAe+9PsDpp8n0jUpjlaYxyTTmVwQtrous/85m7uSO/gy+ldaBHBCcPgJ4ktRBoP5Txf5wtdA2gxSDou1YoRQKB9uH4kTB2Pq9xyEHNvrXBjahuW4aKZik8n+/mL0UH0xkzskfb1gc5d3aXNCySnzpuFxEfxpu41fC45wH9Nbca2NRaJKKujcxAiqBJZ274IHcGGscfJukGZXZu0gjyG7nEJEZbaAZFmiw9vqUou9oMXUJ8Iqijel9qIAHa6I3R6LpYRgFoieggN6Ig0UyxadLou1yTXTw0UET+g6DRFgwPbqWOjuDO9E1MFHNcbOpbxqWQ/AOuNToRU+IArBFcl19FntPCarpV8KtnPfDu4xtelthCWJs+XzqIBrUojonwKuCzUS1jyRQQT/i32f6HH/AfbP2giqAdOVLjJWMqvEpv5gXMaLS7YZJvEe+tIQ3FVch0nVi5jjivAcXHv/WdOrlqG60nuSu9iS+fFZDWdvePHeVvyMha/PYDutnmKLSvONcQyA293Y11jkSM5t2kRf7LqDOd0g690DaABf5JcxwdTm7jED7Hk8AE21jWaQjaXuxYrVo4Q9uGxscN8MLWJH7vn2DF6gGf9PKI5QlEKmhtRwRN+hJ+GDDQUZsRl8/hjdLrgKcF/Hh/kaXuEbk/SFKqT3rKIi+wgyeN5gg1GF3o8KLe6bPhJzg03E0vUaFcaDsHUcVLZRFpsrrdbuC/zGPe19fN9EeMzm0a5OnkplvD55PAgEQXzQx0YCG7+kyIOippy0RsiChHdQVdwq7aEFmESIkjahZFYKniomv7TV+lVdYRQeCjeZc6nOVKjxaxzzcR2ynkLvbcFGdcpFEPYrobnSZpDdTp+fJSwCqbSiX/cy+o3TfLu8e0AqIqNjGjMt30uX5shEnYQpsQIe6w+uxdDKYyIhxVzuWl4kJDhMlcFs4Rwi0NSBbqOp0xB14PH2NZ5Cd9IP0JS1qYqU77WOcBrPmZhhFw8T/LDUJ25bjAbCsdt2s2AOCmonVe0eYpus0pct6f4gmM+PL+ngy+beZpaakSU4J1vHscUGkkRwvY0vppvx3MlHordXjMjQ030eIL7W7dy1pB8IrUVQ/O4dmI7rd8+MNX/P5Hayu3dA3R6gvnKIi5MysLnjF8hFHZwUXTLMHNljI83r2OhkaAVnX19q7k71sQnhwdJYXHTZJQHnQR1AaOazlxX0Oe4KASdLvw8DNGQzXtSG3hPTXGdGmtUQih+2CCP6rSa0RD8XXQtTU11InhUcSmd7ys+XOpadMswH09t5dPJfpY2VGaivseIX+FcPUu7L1ia6OV9ooym+7R4Qcjk/3HihNBok2EOU8YVgpDyWeTpXCNTvL1lJR6BUsx3wy5RdMIhhzfoKe5p63/Fxhzlei/58+9h/yEG5s9GpxNH98oJhi5gRMu/IDfw3JlppJX+rg/MkCJarU8njt5hR3nynulKvSf2Jel7z3TicLc1fcEferqXtdbk1PoNdYvb1k8nUepiOgmRPRMhccG9eq+YKe91kZo+l3WJca7xp9f3z101tfyD1m28X5sztf7zQ338rRqaWv9ieuf0Oc9bxaJl02xkB2WNd2+dntr9KDwdX/0zUeTDD08ztL1QI+1rP2yeWl4hm1nTvnBq/V/MmZOb+f70fSh+/2N81pguS/yxl5lavr91Kx1Lp7e1tc6UIRp/x9Kp5cnr13HkV9Nozf/D3ptHyXXV976ffaYae6ju6qFKk63Zlixbg21ZtoaCAHEIBi+IF755JGYwScAhEMfPPF8nXAJhwfVluAQzBDNd4osfgWWMk+AYh9ZoSZYtybJGa1arq6q7q6u65uGcs/f7Y5e6JQXZInYWWdz3W6uWqnROnd61zz57//bv9/t+v0b/dCLw0J4+dlQvTO6ez5z3ucHp3/LHyVtwzxNovfIiGay6Pz1wlsga5Z9NJ1YfvYilrtOYDoOUh+0prxLgi+VpRN7SNxV40J1ue+zbL/GVudPj5o+i+an3v9Uxzowl0wm+j44OcZc9LTM2+WfTOfF/rJ/gR940krNxEbL0y+fV7j6QGWJCTrPYffY8BrYvzSry9p7ppHXWAuu8StaHz7vOU0GH7wSn+/7/ilwopfZTa7rts0WY2db0OP6T8xCq22Sej51Hxbna7OW/BpdMfT6fLXBz72q+JqbH7RUizLvbKiYAu8zpfn+i3sv7mtP39CVedeP9q9n/7zG/ui0+tl+DPXJROgybmoB3W7PxS4o9ZpPc8QjNksUVIkzGtshYoFwXWnV29F9PvhHk7uTNDKsaUsCK+HwMpbCFYtiUlA1BzTBRk2VqpQB/m95CAMF+22fGtmN4Aq47u4fvyzRFA0YMh/t2xqdibSdsxUgtwnOWJjFK27AoNpO/S2+bglE/ld2Lqre4JbcTF8Vut4tazaHpmRRNgduwqNYdNtl1PGWQtQzSplatXpHezaSpk39fGUhRrQZ4f3INxeM2t+c3M1kJ0qyYuA2TT2Y2UpBNHtmSJC+bNMoWGVljw8BS3j2xkaara5QfzzxPUVkYCu7NDjHmlsgJnxHD46iqEjfDDKsGE60yNc9GAo9nnucHmZ0oFAUvQENoUduwsKDV4P5WB5VKgLJyKfsNqg2HQitITRhUMxYyV8Ybc2nUbCxTYghFrWUjaz4loWh6JrLcoOBqTuxa00ZOVmgM+2Rtg3EcPjA+hF/ypkrbAGoTDs2Kxf3ZIapNh1Hh8fX0VqrFABPCZ8JQhKUkm5pP1i3ytsEVTAqbTLsipiVNGiUN0DmXd7h7fIggBqVciM25g3wqkWLCkAQ7PZrS5KgXZcwLUmzWGDE8sha4OY/1+e006xY1oXhoMEWzrMNOtiGpVR3qNd2XpXKQ2pjFuAkF0+T78Q38Sb1F1bV5rHcDcrJKzmTKC3w+d5S8oTgk6nht1GJJNikUw9yRuIGDbp6NtVMAjLolcrgYpuK5mubPPkuTetGmNBlkHJcFRpUOCWcsh5cDJgcdPUHnayFOeJO8KIsM1yK8J7majKlRhACu9BgTHsea45iWJGc4lPHJt2P4NUN7+Me9IuO0ONHQNJ4fTa6jbJhkaHHSkmRMyZHCWU7ToFG3CSjFpLRxhImJVnavoWvTDQVZU7K9epotbT7wjPDYZYdwkRSrQfbWzk5JUb0u9pseYxZCnBJCvNTmxXj+omP3CiGUEOIV9a3ONcQ0JL0ioGPCgBHWiQ7b8TEsjeQKSIid6ysnRCTUoi9cJ6FsfpJ5gX7PY6SeY5ZZpyvcYIZv0O/5hKWPCAUIhtvQWQwMYOzW+VhKcwH0mGEEuhxutnIIqun62W6zRRwb0/i3N+rPk+u4O3nz1Or6UHoTHxgfIhJtEQm4BCTYQY/VY7voxiZkelhAl9TSQzv6r5+qgKi3QxezlcP8gwf5Rn+KYJtRy7TllBxVUMEisxMhYJYRYbap+TFWj+0CdNz7tsIWKqaOpb+UP0VcmfxtegszRYikCPHDjBbCdAyfT7c5DN46uJxQe1h0SXisdwPBdlVGQEiE0BO4j8Q2fcrCxATchoXRFcIICyJdTTzfIBDyiAZbCEsQUoIJP4CwTW4tbCUoIWB7qHoLM6Qlpe7Ib+JLAymMqIlhKvZfcS3f7kvhhD2ctvp0wPIw2xUowbBWKO+Vgg7hMTh0jDmBXlwk3cqlTzhcd3YPb8g/q+PdpRDd0QbPxNbwp8m1WOh4+Kqe+fxlZojPpjeBUETtFr8/sZGsbTKvM8Fc36JLgtWjYc2mqehUBgubPkoKltt6FxcIupim5Evpzdww+jyBTo8H27zGPoK4GSaV346tFEZ3hI9nh4hKScLRnmu/FEQweTK7GwuBI0xiXTXCwuQKq2uKCzppdxHExLJ8Voe13FwHFqYtCYZcQhg8ZoX46OgQnb5Gb8bldNgqZoSoS5fbCrqaKCQlkS69iLnKJ6ZM+iw9nqLSx0aDU4Z6bsJSEFEGnUaA76d34LRVeGdIk7ohCGOS9A0+15Z668Ci1rKZNAWuMOg1Q3QI/Z2H01uotxf/Qd9gRiBG0u4irCCmTK38o2wCls/JYpbHXsdQxv8pHnOqzYux6tx/CCFmAW9G6129ou2bdR0HZYkbRp/HRZFrC6uqNh93sRjEMBXjqknT0KrBwjBAaUSd6xnso8zy+DyawuCq6EzKno2UgpyhqBkGvhCceazCOUGXY6rGF9Kb8Sq6EsJAQ1/HTM2r8cnMRu5vl+YMSkHVt7ERNDyLotD8BW8bXAHASVXjm+ltcFE8yvcFX1ZBPAG+a7Bv1nWMqia+EpgKRgwPCTQ9a8rzvi87xJ4ZK3hOFRm5eT6ugHJTe3lKChooJmWDigGjqkm9ajOuGrjnrezptfPZNHZgihC+Vxrc1LeYspDc30541trb5TOlMUyhpiR7/im7h6OqiotgzFB0SQ/Rngh9BEIo3ptcw8H8GSxT8q78JiqGwGqrwcia5rawTEk214HnGyA1ZHfArhN7ZB9nVy/gA+NDTDYCCCFoFQ0eTGzgKwO6BE1WfM5pCHf5ktqkM+W45N0gnUofbNRs7k2u497sEFsCDiM36+TfU9m9NDCxmPa6+9+dxJMG0te80H+b3sJpVcf3BdvHp8NhjaLNDvSklHA9Kl6DQ2aLkgHxfzhCTZl4nkFFSCZNk/8yKqniMeEFaDUthIC7kjqZq3zBlwZSFEzokj6jng7xhJUPhm6bg2Tj6H7uS67HBc5Ifc7n0pv4+eg+KpUA301vp6Ra3NS3mBXx+TSUx8PpLXieiYPBj3rW46OQvqBaDdBC8Tt1fT8MNGF+n6fh/avHdiFRbBo7wC961lATSgOg2l0Vt6KElaDg12g2LCqGyUvuBA8kN5BqJypzwqO3Hf45UjjLHyRvYsTwKRuw2x3ncJunY7icQ6JwTJ+GgJxlUJItTsnpsEStfZ8/NjrEuFtmthll0tCQ7N0BSU54egwBRVPwV+2k4ms1JdVlv34d9h8ZyvgiGq79H/rLmo1X4h+70GbfcflMdGNvnX/JY+c86cuxD7qvE3/sxdddMXzJY8ktxy557LXYn/4b8d9/nw0fj736SW07Y1/+EA1fc2lWvbHHLr/c6npZffWT2vZo3+XTUP4P1XXJYxeDNF7JtowdvOxzx63X5xG/zbv8Pvlqeutln/vAeUopF9sc//L79le2/+Qe8+XPapc2BTwthFDAN5RSfyeEeDswopR6UYhXn8T651f4i739fPOGhXztbIC3NJo8BDhzdI3nvN+qgjT44XPP8RcDq2i5JiKeQFgBBq4s0apYvDWdQIhO+kSdoLBIdlVwAh5rxzx6Ag06OxuI3tl0XTHG98ZTKBfuiq0luWULu5Od9M2p8PkzKdbJMpFYk8d3zWKop49UfjvzWi6L546TOZ1k3qIJKocG+WRhmA8NzOcvem5ifWY7Dw2mMGYYnFq+iOdOD3JdX46OwTqRSgvOQPd8l45ai7t2JxhMTBAttZhbC+Eqxfyrcmx7+Ua+7Zi8t+WTWDjBbQdmEV4iufF4mcTCIsEZAtmQXJ+1WGYMsO/ZJm+2AyRXZ/jJ/6tFYp5PrCQxt8gzR2ZxylbcmtnItviNtKTB3mA3v91occYIEpHwrvxWvhtPsdvxSCbG6D8V5oHkBk7T4E2tEEsSo4QyMcKmxwoVge44TwxGCMWKXHtsFp8bTNE3c4QzyYWMjZToWeNgJPsJmCbdXh7pNUgEy0ycCGFf2cW87YL+ZJniB9ZR+NkojMPVS8cwFy+mM5zhjicmCYZdxieiOAt7MDtLzHlB/67fXzEfI2jwxPF1LJk7SuXkII/1bqDvqrMs3NXLpp6b6AtPEPv6S3wwqdXOFw1O4Gfj/N+p+QwOHaNZt7nqjUXcMY+DzjW8UOzF9QR9Sye5t76Oz6c38y+xW+i+dgK5u8LJ5GJgnFVjs3lLwyKqXIofX8vYExN0z3e5YVuMd+aHyK1fyI1bQyzsH6NzZhPlwd0Hgnx69QJCCxyuPdwg3lGDALxQ7WFkzQJmPLuVonMz2+I30hUtc1foJr6b3s6ilsfHCnv5TCLFwqZkVxBmXDnCQyJFWELN7Oa+7BCP9KXo9X16ZqWZfSzGu/Ja2SO21KcjN8n6fTOxRItf9KyhL5THdU2KMkAqv50zqxby4+FuPhK7hXlXjhM600VHtEmgUzsQS6wY1zeanA3OpG9RhsUvmdzdTBCPj7LHXsHykSF+3LOegwGdGP5Q8hZublr0SI9ZXUW6qgk+0xPDVQZvLmxjTcth1pJRbjokGEiUOTk+wKBv8Ie9G4hJn/5gja7uOntG+zgWMIj6GozSwGR+7wRmqY/k7HE+Z6ZYQZne5uU7V69ov6Zqi8u112NivkUpNSKE6Ad+LoQ4DDyADmNc0oQQHwQ+CCDMLr6S+F1mF22OqRrzzQjfjaeQ5QyfSaRonR2mHZZirBUiY1ksq1RQvkt5NEijYXPSVlgKBhs2FVlkstJJp9/kjGXjNwWVnM1grU41bXHE0XSME5ZF7vaFbNsYxUgr7s0O8XjPOrpbNhMBONBG9p2wbfrSUfY5PitHwoy1obUfGR2aSt6cMjy6Pqmz3l8cSDK7oBeVWtVhn4gwe6JAreCwN2iRKAZZPrKbR/pSNAW85dmjfLsvxbfSQ7ypdwP96QBZU+FlalyfPcpLgWvpC1VxqwYnbMVR6kjCDFuKxrDPXyU2UBeKibqPdVpOgVVu7FtE0XN42bHIy0n22jqWOWIb3JG4gbsyQ1zdM5v3ZuNT2fG3Da7gsBNg7mgnhx2H+S2Dj+eG+LB/A7lchI6GxRlTK2//TuBahIDxRojkoSzh4Diy3KCcdfBdg1CXi/QNZKFGxeigWgzQU6qSy0b5cc96JtN5IqUKstzg5Wqc3qpeOK7Kj9LKTu803KKAkuTthc3sn7iW047BfdkhhscXss/ykARZ3dAx0j3uOH+QvImxccmmECw4o6sWxkoRuk7WaZQdfM/giI2uwz5jcELV+Fp/iqMC5r8IxckQDdfClwZps8AZO0qPb+ANZ5ksRHDSZYZtg5/G1tIay3DWlLSaFrVxH+kZHCPMzTt2MtY7n5NmkFbJxEdwV2EIcjqfoTyfm3M72Re6ju31YZb0zOGQY/Hh5FqO06QZcHCRuDWTw0aThiHx23G4rXYD11YsSofICN1PL9uS5oikVbXIWgI8h4ohaJYMxkyblglb4zcyOdrkOaOGFwjTl4mwT0RYWDIJF3X/nZAVdjkxsqpC8ZRDrhriRFBx3WSQFend/Cx2C0dsg1OiyUeT6zgoi3x14kUe7k9hFqMcCykCMsDv5/V4OuBIbsoEqbg23kgXI06Tlunw0VFddfREbB2NcYsJy+CBzBDvSKykz+hg1BIwESMTVBRGw/yzHOP+MV1i+LrsQX9NnvDl2mve5yilRtr/jgGPo5WxrwRebPNozAR2C3GeaikXcmWMpq7lqOmRL4TxUbxvfIi0DY1hnwcyQ5w90j1FZFMwTe4eb29/vBaLj+1HKcEwDf46s5HfLWxh69ghbsntZLIW5GVbUhcGqfx2Tn+nQKtucVLV2SEquLTlfwImY9Uw70ispGSYpPLb2UuVg6bL4flLGbEUqzIv8IX0ZgxTMWrB4tgs7kzcOJUpfji9hcl7VgJQMhTbDC3V4/kGdQETwxGE0Ex3+5u6hKhiwIileCa2hoWqxg96N3DUESw8coBPZDbS96TmT/B9g1I6QG3SoSkUJ7xJGgJ2+BMoCYeokkUrRIxWpz2KT3j9bA4ZjJiSZ8Zf4qzpc9rUfXqoOcatg8s5mD9Dram9n8WxWTyZ3c0ITU6IEMdMj98p6PpwqiWtQOIa2AjuSNxAR0+DiVKYvGEhDF2TrBoedtDXXtpYiIOlbnq+f5BTliRd6oCAzarMC7wzv4ncZARVb4BUVAwDhSDme2AIzDDsTq5gqOcm3LqBYcF34ymGix3clx3SE0FAklZ1JHCw0Unu9oXMtDpxlWSPGWaUFlcf18oyeWyqeYeD2Tg7aj10KMEnMxtpVm08pRNk94wOYZj6XmdlkJoyOVpN87HRIY7bit5HD3GyFWEiEyFvKG4rbOG3DrQ4qmq4rkm1GKBetdnqtBi5eT6VYYv9to+PoC6mH7WWMun+/A62xW8kU4nSbUUYqeVoCqji8a30s5SF5BfNs1QKQb6VfpZH0zt4LKMh1PNUcKrkb1hWeSK2jjI+lVyA4bPdHDM97pzYyN3jQ5yybTqlzwu2yy25nRSqIU57umxvRXo3PzNLHLaCU7wjLeVTFYoJ2aDVtHAx+HRmIyvSu3kmtoZbC1s5bLp8K/0so6pJ1tVldYctjzOWw8/dNPc19/H+5Jp2v7uUywEOOgGOE2bYr5A+x4gX6SZrm+y0wuy0GqyKL+BQY5RJU5A3FDnTYo8qUqoHcNXr6+EqpS779euw18rHHBFCdJx7j/aSdyml+pVSV7R5NM4CK5RS2UtdZ/R4Bx2YBGyfF9ty8A0UTrssuSdeRRhaEj4sFXtmrIBGE3xXy937Bo32jftpbC3vSa7mp7G1XHN7jX5pUDME349vwHJ8fF8QEzZJEUQKqE1YzHAVLzsOvlIUTPjH2Fp+mHmOOe063pgUbIvfyEeSa3FbJjlDMlLVdZ9fGUhx6+ByLTPV0mt5TSiubrqUSkG+IYJEpeY1mCyEqBkw4OvkyLe9U3RKQQuTYRViwhKMC4+XFy3h/uR6sm+cz+M961BKcGhMd0YNyYdUkpKhGGkVtJagbPL99A5uK2zBRDL21vk8kNzA7xS2sKQl6JcGru/RqQy+lN7Mh5K3sDDQhy0MNvXchNfO2I83Jnnz4LV8P72Du3JDZFWTR/pSOqYZ0YuJL3XG/YeZ52hWbc1PrRT54TB+oYGs+VQKQZoti6ZrEVWS3O0LmeMbuAhUtTlV1+wrAVLhl1x6fI9R4dBvN1ANn1rW1GWE2HhNk9qEzaQJASF5MLGBUVNRL9h0CZuGAX3Sxc1LjjTHKKgmM1yf62SIA3OX8UxsDW96v4svDXrNJlerGvdnh3QlDTDmV7GVrq4JdHr8oHcDncrDRDEzFOcTiQ0kfEHu9oV80y7Q0dUg1/ZU5zlxXCSeb+B5pn6hyJzo4vTZGF9Ib6ZomDSElgADKAuTyXtWcnNuJ7aQNKXL+3pW4p6nTB5VBlEzgGX5U8nEvrCOUZ9TsDZNLfM1YZmMqyZ20OOrjiKhpqlcu33FKdskoTQP9fr8dp4dP8x92SHCdgATg5CERtnmgeQG0q1JWkLxi9GXqNdtAm0I/zsSK/ExeLR3AxLF/O4klhDsmzjJ1/pT9CuLkFSstgdY37GAAXTCuqy0QIQP9PsubxN9RNqowbs7ryMgdTlnDzYJq4OFgX4GPR8JPGlXmGGE6Qi2KPsNftizno8kp9W6X5P9J48xv1aPeQDYKoR4EXgO+Cel1FOvvVmXb0330gmCgz+5kD1rxrs6L3EmLPPqF3weWbPgkufO8S+/2+5sXPrG/p5zxQWf/0lM/vITgWtmjV3w+cO3ZC5xJvy3PYOXPHaxnQ8JvthmigtZ4c6povwyO1eGeDl2amv0ksd+YV54LPgr1JEGF1xaimjHI5d/z64wLs2U96etCxN4D8+8NPBh4VUXMr39ldO65Ll7/cJlto4p0YNfZg9YF7LAReSlPc2nuy5f9e3jrzDmf2pcOG5/0Pbsf5n92L9w3E68QjD1A43LonL/99lv8sSslDqhlLq2/VqilPqbX3LOFUqp3C/7/jmb/SaXGZ6go6vBsUmdPY9JgQgaPNKXwgpI7C7Fl9Nb6FIuy0d2Q1cnWAHi8SqxnhrLiPLQYIrbClvoxdG8EaEmvT7MUQ3ek9uI6IwSm1nnSmnjo0i60DlP0il9YtE6VxsdXNVy+d3CFh45OUNzdsS1HNTNuZ18Ob2F+MwKcU9xW/xa+oTDPaNDLDCi9GIT+zudrLquKbi1sJXE3CKzByeJSEVHT4MZC4ssaHoY7UKVBS1FTGo6zcXBEj1GgJUti+65TbqUweC/HmOGXaM3UcEOSpyQxzLXYp/js+2ZAY4UzhKZrVhidvFXiQ3smbGCZE+Zr6a38pn0RnYNrmLMElMKw3Ff8LnBFF9Nb6WlfJbTwfr+JQz0aOrPP4wt5+ms/g3PxNZwhW8yw2tPuFLyVHYvvYkKnx9McXfyZnoWNUn0lxgUTboW+Nhz49hze0iudenpq9LbX2HB4ATxx18mIGFmpII5o4/BOXr7OxCrYMS7sed0EUCxrCvPrUYRozdM53U2J5Yt5tbCVqKJFt3XwlUtl/7OKjN8wQ0Nn+4lipkqwL3ZIYKGLkF7a/BKrjO6CCuJK2DJiX38VuFZrluVJT6vRtD2cCytKvPN9DY6Bhpca8eJ+lKHqhywLZ+eYINkVwXbsIhJQaeviD/+MoNOHTvoT6EinQ5JUoSI9dTo6GrQm6gQx+aKNWXsbs2JclWoyFyjxjWndd8u6pik+ysvcHDeNfSE6+ydOEHeqzLHFXy+jW6c4Qtmmp0sPraftzT1BDVe0yGIGWaEH/RuINrX4FYR5xqzzGoVJdilvfhoey3LGj79doOPjQ6R9AQ3jD7P4flL+UhyLd+Lp7glt5OkCDJHNuhZ1OAz6Y28ITSHJS0tMzZraZHuYIPHMjtZPbaLLrvJ709sZJ50ODaZZgYB3pFYyVKjk7gPCaV5aB7pS01B3tf7ESxHMsuVdFstbrL7ma0cfhpbyxnRZEHT419it9ClDBYaUYbdSUyluKoFtxa2Mlc6OAGP+YE4d+Q3XYCCfC32f3K53GWbe7aBEpDLRdgwsBSAugGmsMP3AAAgAElEQVTumM8h28d3hU4AwRR7XOdHfgRKMv/gQepVm7/MDE1lrEeU9n4zlSinLcXptucnxwqUMkFOGi6nZZW7ckPUR+CkbZErh3m6dZZjbTj4GaG9m0ImzMR5BMy1gkPOErzUHKWKz2O9G/hyegtfTm+h8IFlPNKX4pADn0xsoDIeJD8RZtQSjKU7qI47nHIsjrZ/w2lbK3Vvi99Io2XRjU3GglrW5KjQnk+2FaJS0PHl3GiUA7bPUCvNacfk48n1NDKKQ36RPapEthYmW5guGcs1gwwbWofNNAwOWC4nDT3R5vwa+6iwaewAhaL2NB+vvsxgVJeyZUyHMUNxa6Fd+lTXnmE5H+RFo8E309uonjUYHu1mhCDNUYUs1/HTRXq+f5DcaJTiRJjnxrTw6j7bI18LIcfzpE9qr9NrmahSBVmoUTAsRiejHK13IIt1/FyTuft0fXE9Z9E66zJi2UyUwoyYitO2RTOtydYBTooQ3miNLE1OqDr/K+RxWDSmlEW2vjCDSsbmdDPKYS9Kob3RmjgTISPrFE2Dtw4upzpqM9YIc6oZZU8lxq7xl9lh1HgpoMfAKTdCreSQaTP21dou3/h4lOxYBxOZKE0kzaykOW5wxFGcqUY5fZ6w6IlSF/n3XE2hGOZ0tYMNA0s5Wk5z1obdRp2b+hZzwpK8UD/L4flLufM8xFs83Mlxr8ghB/JnIxwwGpxuRcgYPuXRIKV6gGFTt+3z6c0clTrncNrS7R/Nd3DIL3LU1p+fd8dJ5bdTPat/x1G/RNYSjHtlCieDnG2zyv2iZw0nff3+XH3/JD7bisfY6xc4YvlkhMMX0pvJWHCoTSD2vNUkPxHm5YBB2g/xnJdjRLh8I1AhK2vcVtjCUcemKWCzmyVs6GfkmKPBTQeNBrnJCPvrl94h/rvMU5f/+jXYf4qJuTziUG8rXMSMIF8aSPEjdxirU9CrTJywj9EeSGGp+EZ/itKn3gyWw75Zeju2vn8Jbx1cjgE8Xxvm4f4UtpD0SYGt4Ae9G5j417KOw6W3stjo4HODKeyIJCohZHnsyR3nw2O60uJb6WcBuOb0i8xxBbuTK/hUIoX09fW6zBDfSj9LQwhuHVzOe5KrEV1hkp4GjbzRrdNqmjQ8iz5PEXQ8Wk0TW8FKUeZ78RQ97V1m0Xc4psLc0LL4eHaIWsnhO+lnyayfjwEUSyHC3S164lWq+AxYHbgCjqsa0hPMNKM8md3NCdvmDflnp2KnvU6Dpa5JSAmSkR7mSJuvp7fy4eRaltq9xEWAzb2rkUp7anOCcbKVAg8mNrDYqmCiQQkARDqnACthTN44sIxm1SZg+IxaghnPHtWgCUtwfOlV1F2NkpxnVqdiyo7hg1S02vWphqlAGHi5FgElESjuyG9Cljya7SjAE7F1OFEPr25QMMEyJJ7QPNZKQhAN4kj4GmG4qXKCH2ae410NhwQO0WiTHf3Xc9OSEYShuDJYZqbUi94HkzcT7W5SVS4CDa7xXYOsZTHbrtLl+wxGY3QLm5g0yP3eIpJGA9vx6VEmP+jdwP3jHWRVHakEA31lOroaVPGp5R3sDsksT1AwLd49sZG3Da5gc+9q3l7YjLBNNtlhTBRN6XFFdABLaYmobjOEh2LA6cTzTP4gedPUPc3VSmwZO8gOVUAIzYs8YRm4KJyQR6yzTp/U/fulgRRdvs+/xG4hqgRb4zdiGpJ+M0xR+Ozov54rrC4e71lHrezwqUSKutKEVoN2J5Yj6RAef5pcS9RucefExikR3dsSK6nh0x/sZqHZRa8y6ZI+H0zezAFqxJRB0HKmQD5zWwoDRacR4O/S21hkdHCTiPHdeIpr3AYhJWj4LVbafUg0wMRQih5sOkNNVoZm8t14is+ex5fyWuw32mMWQnQLIX4khDgshDgkhLhJCPGptt7fXiHE00KI5Ktd528muwkpeHnREhIiyFUtl5ucBMLRkGUzoBCGhhavnZXBVoBtgd/WOLMkK61e+owgM70WYTNAj69Y8R49SVpKsShQwjAVQsCDiQ2sryvuzw4xOHSMft/llB/hrYPL+cpAih0Bn48m1/Fwf4pjV19Nj+8RibaQ7RBEU+gi/w8n13JXbohBI8QMAnR/fgclQ0OUa76FE/B5KhDEAKKxBlcffwlbgWP7RKTkH8w8XxlI0WPrUMsf5ob4ZGIDTsDn/ck1WJ1tBrSAy+kTMayAxENxtdGBBGLCwY5I7qgb3J28mQ+PDbE7uYLPXD/GHydv4UN+kcWqxicyGxku51jnV5m8ZyVhDMrK45vpbayb2EHIcbk3O8Q9bi9PxNZREZK6a5ERLh3K540Dy+h4++emvGcDeJPoRQhFyHFZ2NIJSwDhmJxJd9MZahIIeXjSIP4PRzSsOaLJd65+a4Uf96yn3rCRY5NYcYe0pcVP919xrYZktxfic6TyviuoCzS/M4puH1AC1W7PcdtBNiQrIrN4MLGBhFUnoASBkIdSguitC7CDOkn3xUCLe7ND/F16G9IXLDW78QV8djBF99wm7xsfouWbXJ2Y4J2dS1kgbU307ym+5Wi4+BFR59Y7y3QLh3kiQle0wf5RzS53jR9A+gYn9/VQMmCG3+TzgymCwqQz1ORfYrfwtZ/FmdtS/G5hCwHD4g3B2QhAAHEjQLcy2Tp2CKU03Pqb6W28I7GSLw6k+FQixbVGN07A4x7RwFRQxMOwFJsrvYTbc0mn1JSuZyybOa5iqxWmM9QkL5vMkBZ/Y/jc1grRFAbby738ZWaIgLBpCS2dZgV8XGVQxmO4Td50z6gWGPhp5gVsBAfyp6eUbjoNV/cpik9kNrKqZx5/pBr09NYoG4JBs8EdXje3JVbyVOMUZ0WLcFshZNCDu+0rcVEMeIqoMtgZVATaaNMOYdHve1P8Na/ZfpNjzMD/BJ5SSi0GrgUOAQ8ppZYppa4D/hH4q1e7yHfa3uk5G7Euzb16xZ4jF3xe9PK0QMq5jPY5O/mj6YrHfD1Iz63TzHTPhi786fPPk1h6e93ngWunkWLHnQszFKHz8lEXUxG++yKildvPg58emHth0ua/eBcyqa2IT6MNE21qy3N25aKJqfcxZfK+1PTW7oehCxNk/2PX9Fo4Ki9M4J0vLXVH4oapsiaA710kM7VATreh/MT9U/zN8G+VJKL900mnZPzC6+Tfc/UFn088Pd0mY87ABceeqV/YJ+55AKUHL0KJSW/6WNL1ceZPf7fkXth/2x+abtM9jQv7ZN9Fibdt8Run3h+46Nhd5yVzn/pBB5+cN83mtnTgwlTK3BXTbHP3Zof4m87ppOKH7rgQSXe++vP3L2K/y6vppOFjMs1LTH/3v8sLn5U3xafbM2wpYsb0dy++Z585j2HxjckLQwXLeq+88LeEpvuveRFm7N6Lrvvb3nTJ5j+IC5O5j1rTfRLBpGhOP4e/MC6U23p7c7rt46rB62ryV3j9Guy1iLF2AeuAbwEopVpKqUml1Pm9G+EyINmnli9CAguPHGBUNTGUrgsWlsEnMhupjDlgwFFV47HeDZTarRYBPQCkbxBTJu9NrsFAETBseqSHUhoEElE+ZWHp+lhbMiJaBJTgz5PryKbmayIeQ9FtBFjYavFbhWe5/8V+un3F/IMHmTQUzbrFhPCRStBs//0amlvXQ5KlxeTHbmTfrOuoCUXY9GjWNZdsWEqUFATDLhOmrm1+V34TVUN7IE1PT/y7c8ewEcw/eJCS8JENhY3CdnyUrwnj+7H5uT/GI0MJfBSNSQsLQbB9KwNBjyYKG8HfihgVw+CzgykiTpCdRoT7kut5KL0JUwgWE+Zb6WcRQsfEn8zu5u2FzVOUowbQRGiV7GCYX4y+REdPAweD2xIrsQI+5UYAB5/klmOIgI1q+dhBD9v2Nbm/EsiGT8WAZsuCNmLsnflNmhCqvV0c9CQRSyuFGJHpSVUiaBRtrIDk230phFC0UNyVG8KwFFe7JiEJNgqZr/CTzAvsp0wLzWfhNkxuGn8OH4GSEIm0eD7ocH9yPe9O3IgVkPyxF+ePxob4eHYIvwaO5WMKRb1qs3F0PzUBUoAIatFY3zWY35ZMMoO6tLNY0bXAluPzglln0cv7UZ72WsvC4pnYGv6s6NBoWYQMXatdNAXPxNaQ96qsiM/HUVrU4PbEKmJSL9TBsIshBO9MXI+DSUt5zBUhHkpvwnVNTnlFPjA+hInAMBWmLakJHRN2gYY0WUp1yjOdrAXpFg5dEhpNmx85Vd49sRHDOlfH7OG0Q3V2SKIQJAngenp8PRFbRwPFmwevxURzLj+Q3ICtYFLafDi59gJNTA9Fs2HhKKj7epzPFREO5s/QqUxivsQxfUqmlnwLY1AxBC20JJhAPy9VqeXhwr8CHcIr2W9yKONKYBz4jhBijxDikXYtM0KIvxFCDAO/z2V4zPnRCIdNl70zl+NgcFduiIcGU8hGm4jFVFRHbTqFjSs0XFGO51FunecTK6nVbZ5TOmP9YiBAtxniLYWtSCX4TCLFwYBN0TB1fLNmUVc+n8xsJKoMWmWDmmFQqgd4NL2D05bD4z3r+E76WU46YmqLXqoHGFctiqUQHtAb6mCiXShfUz7fTW+n+4s7WTa8l4fSm7AMTbBUrgZ4KWhSrzg0ajZFQzHZLgNqC0GzPr+dLw6kiIc7p7ieLQSypcVIC6UQvmvo7+NTUy5nDA8XxXg2qgmU2qak4AfFfZqkR4ZxBQwbHtVWg1Omz0PpTdyeWIVUir/ObCQZ7WGyHiAnpr2n+5Lr8ZWOpY9aFk9l90J5kmdiaxg+FZuauCdzYcrKYtRwOLV8Efg+vY8eYu6+w3iegRXwsQ2JrPlMCp9VmReQ+Qr58zxWOV7Az7tUDIOsH+Te5DpkuYXyBbsGV1EwDcK9Lo2SzQlLcajeNcUuV8kFeMaqcdyWOlZ7psX6/iXERICI8DirNEji6djN7A1amI5ishTigcwQn0tvYoYI0KqZF+xypAdKaSXz06VOVsUXTFGL9v7gMK02iRFAwRS4ZUFWNaj4NvlchLPp7imPtzZu8SdjQxwKmBx2AtjCYPXYLsZVADmplUcMARWvwe7cMU6aHpvlBBXZ4ojpsTt3jEI+zKPpHWwtHWVSNdmTO85n05u4dXA5hVKInFvm84MpxmSdetGmMB5m3PA5bgbICY+DjkaePhNq52gcl4ysctqSZJohFulHlmbF4t7kOhxhcdb0OVgeJnOyk4Jh8VTrLNlWiKdjN5O1Tf7Fy5B1S0wqlyOFs4zj8vHsEEXTpIHP6XYYauvYIfb5k0wUwxx0JBVlYmMwTos3DizjBVWkYBrsJ8Jxw2VO5wDHVJV0e5E4RphhNFPhObmt10vzT3nqsl+/DnstE7MFrAC+ppRaDlSBjwMopf6rUmoW8Chwzy/7shDig0KI54UQzz/pHmehb9PZU6egmnxxIEVIgRE2+eJAiugMl2jCJYBBQCq6fIXR04UwbHr6qlRdmyezuykpl1ktybhb5rmBVTRciy5flw8lfJexJyYQhuKxzE7uT66nJRSmowESve1tZr/nYyrFB5M346M9kKQv6Omq8YPMTkIBl24fVnReyRxxYd3s5L2r+efYWj6Z2MDqsV0Ewy7fsE3mtRSd8Tq27TPH0+xmj/eso0tqNNvm3tXEfPifoRVYCo5drbf+ZlTL8QRtj2CPT1d/nQFlsWv8ZbowGZN1Zi2e5PcS11PD52v9KTzP4KUNcR5MbOCarjx2e/cRtgMsadd8R4VFl9DezaPOIrpDTTraqiu3JTR6Md5RIyxhnt9kVXwBBIL4GAz06y3tsDtJMOTS79SZsARKCkQ4xMSdizl61dWEIy1KuRDHVBgrHmChp68vbJNVv1vge/GU9qoTcazBIFEp6VAe17RMlNR5hXC4xWyvhRmFSF+LhC+YQYOEbI+Lvgb9wmHQNzCRBGY7bBo7wAA2LWWyjAjBsEvE9LjnYxFqBZtwwOWL7QSWhcAO+tyeWMVXBlJ8JpHCsOCoF2V73w0MBOo8nztKvzK5qgX5P9SLdCjq0ikFSdfnHcdghgjSH67R219hMF7m/ck1vLxoCZEBj0f6UixqShKupEc4PJ9YSVT5GN0RBtt8DTeEZ/PR5Drm+xY/H93HbDM6Ja7bN6hDYcs7rmCWEWFWh2bQXSu66emqkQpfwb3ZIbqNAKEul46uBgs9k+vMMl9Pb2XQU/R7PldIix3916OUYOPofq70DJLBGkuaegyatmSWb9JpOCSlydKO2cy8ukhY+syxuykbJt1Okz8aG2KV3c++iZP8MPMctyVWEsLgywMpBnwtZ7WXCg/36z6+xuwm3l1lQ90njM8/ZffQg81cs4ObRTdNA1baRea1QzK+kvT7gr/ObOS4rbjFCxEOuLxxYBlvL2yeunev2X5TQxloRN9ZpdS5avIfoSfq8+1R4J2/7MvnQ7Lv7Jn5725EtXj5Rej9b+999ZPa9unlo5c8VvgVSK/+2Lt8ZP+3z4u/vZrd99sTlzz24J6BSx672L4auPz2/RmnL/vcV7JjT18aCHKxvbmw7dVPaps549L39/nPXn7fLrQvXy3jn2+8fI/qL5xLA1c2tS6fue/8WP+rWb+6NKjlV7FFF+UfXsnWyUuz/F1s1VeITNzc+I9hZoT/9Dz5//6JuQ2xHhZCnNMNeiNwUAhxPmTu7cDhf/Pli0z6Agsdu4u0s8IeOsNfNTSJjbB0aZCN0lJPUoHt4Hkmdpu83kdSMg1eyp+i7tqa9B4YN+Etha0QmI5dNtuh7xnPHqVuCBpNi/X9S5g0TRrCQDbAaHsthgLbmd7q20DOr3LY1+GTtKcHrTAMakLHxWGaktQTYFhKb+0VbOq5CR9Bpw+ugHUTOwhLyb+O7uPu8SGsgM9JVaP/n47xzvwmQiEXJXX/5IXPLf1XoZQiKEykB44wCWLyJ2NDmKakrDzsdn/67YHfGQhTbd/tUVnn6+mtWpFcNrBtn3F0ffNPMy/wUHoTzZZF0QRPCTrNIAiDqldHGHo3MatNiNTwLEqGJvE/Z05Yc2WcqXQwRzVQLX+KeEa0E6mOUpiW1NU1UosghEyfu3JDCEsgHGg1Lb4bT+FXQBgQUGAIRdFQ1A2QrsG40oKzAF2f3dIeB1oEtygkwlC0pMHiJWMoKYhEm5zLGX4uvQnpC16qpwlKyAkfw4FKS0PNlYLreufyAhXSlkDYJgKF7xqcMD0KpokwBAEMPN9AtkMc30prYn7Q0miuEISVTyjaoulaNBGopktNGBSxeCyzE19JfLQ6SFl5U+JSzarF2wZX8FR2L7uaGQaDPXQZARooTFPhtsexg6FFT32DYVPhS/33LaF3IkGp4fTN9s7FVmAaerfoCf0MVs6bDYabeZQHHcJjoI0DaHgWn06kKOFOee4Fvz4lrGAJnduoG3pcv2HgGjwUliXJWDZ2u6JCoPUqx4RHROl2pQ2fwUA3EWHTaN8fH4ErdCgz0hZjfX0izPxGe8wAfwo8KoTYB1wHfAb4rBBif/v/3gz82atdJH5Ni6DUSTwfLSDqCvAnWzyYGUIYICzBw+ktdOER8yWdf/k0AMtHdk8pfPwkM11xsD6/nc5Ig0OWxw2Nttfga7Xtzw6mqOJzVUv//JgvaboW860uFLBicJwvHZoxxUlQMmHHeD+fSqQIR1pEfeizotwhtYe2ffywJs23Ld6V3zRFOm8aEk8aWArcuonvGiQ8l/X57bwrv4mSqSWO9sxYwR35Tbw7cSPf7ksR6PSpyGlPJ9LVRBi6CmGub1GVLX76ZB8/ybyAFdYadg+nt7C5dzUA16kwn8hspOlaDHoenx9Mka0UcIXWAHw6+yLvTa7hz5Pr+MXoS0hf8M30Ntb3L5mCXacbYQJKe6xV2YJGjeGyrjqYrRx+mnmB3vl1usMNljU8uu+6DjlZweyNMOeFI1iWZOkVY8xbNIFqSIYtPcJFNEzfYIU7JzYSjLioyTLC1orI53xPs78TezCAbeuJ2gyDGRX0+j5dkQa9UjC/KQnNgBukbmdPqEHu9xbxjsRKTeijTAxgwaGDpPLb2XxwJpHeFmMTUe7LDk3V49pBiVQKBRr5FxaYQlHzbI56UbrMEMuJ6ppzxyIe0ovTYs9itmwiG4pa++mVviAab/KR5FpiVzYQll7U51oVXATz9h/i5txOug0XYQgW2hXmBCus71/CvomTSKGdgZliWgzADvo8md0NwL6Jk+waf5nHM88zKXyEUAQw2Ny7muW+3jk26xb9UrB6bBefTqQYQYegCqZOat6S28mbB69lzNTPTto2SHoeXVfoZy0qLHo9GHC6qE3YBE2fHixKzQC+EjyYGcLCYLic4z3J1Vxj9ZChxUdGhygri7nSIelqgq5fjL40hdQbN8Exfd6bXEMULX92StWIeYpCM0BSmsy3Y5z1SjgKvtafomSYfGR0COkLfpp5ge/FU3x09HWKMb+OHrMQ4reFEEeEEMeEEB+/xDl3CCEOCiEOCCH+96td87VCsve2wxHLlFLvUEoVlFLvVEotbf/f286xz72Sje0LUDDBbZk47VinBPqe0OxqM549Sj2j18ox4bAnILgreROqVWd3cgWO5fOJxAZ+e/A6+jyf6/sWAvCvjR5mSAsDxQ971nP2f+cp5YIcNBrU8KeSb+cqBAIYvOB4vJzp5YjSJUnz9h/CVnBtaBITmJwM4Qmo+E0O2T6fHUyxvn8JT2Z30/UZnRT7SHvwuK6JLw3unNiIMBQLDh1kX8CeAsUMm/quLx/RD95jmZ28b3yIypjDz0f3cWLZYr7dl+LIqT6G93dNqa/syR3nrtwQV3YN0sibU+CDdRM7uOb0i4ydQ6W1bI44Fvdmh1jSM4emgBFLS8X/rHSIL7STeC1vOjbzl55+wMP4jBuKf4ytZef4EfD0QnFyJMbLQpcuDe/rYtnwXm4rbKH093tAStzTuiinWnH4+2ySFw4NIluSKpJdg6vwRyY4cKaPLw2kyI9HUPUmlX0NxiyLW3I7+WZfivrePPVjTRpNix/1rGf0YASvpLg9v5lj5S7GDckd+U0Uj5oMmz4fGB9iRXo3tZOK/fUMNXz+PtgkrAQ7+q/n8Z51LOueYGI4wmA7Rn7PuXvUMHhrZP4UY2HfE0cZcoK8If8sJVOwaewAJ0WTCRNiX92t/07Z4SXLZcRw+ND+GA+ntzDaDCEMRSUX4MvpLQzv78ItCj42OsQRP8pthS3cnljFrsFV1KWFiIZ50e9ACNg0doDl8XnEPU2Y/4X0ZrLC5fcS11MqhHhn4no+nFyrY/1t+3J6C42aTRWPMRVgrF0KIQxF/Ty3siUEWdNGoSXL9s7UsPtfoEM7MR8mTJNadnoMTFhQ8KoIQzHshziiqggUqfx2vtkW931/cg3fT+/gqF/iSqXHzLBjctho8L/MHA9mhriudy4AxWKImlCk/RB15TOKVuq+WkQ55EDQ8Bk2fB5N7yBuRThq+RyypncN59gPY/7rGNp4nTxmIYQJPAzcClwN3CmEuPqicxYA/w9ws1JqCfDRV2vefwrknyGUFsIMuxRkg6djN2MAE3cu5t7kOkbWLCCU0JJGUenTLwVf/kgMIUw6uhrUmjZPumcJCpMJy6TgVvhRz3rueneVqISDToA78pvoHqwT6WpSVR6DOJww9Y1+tHcDh2WUbiyWuxa/U9gyxVZ3fOlVegttKh7IDGFbkoIJz44f5gvpzXw8O8SmsQPcnlhF8b41fLsvxYeTa9nRfz2hiMvXA5LvxVM0qzb7r7iWkIJGS2/nd3jjU57bOS/7230pFhw6yIeStxCd4fG+8SFmdJXJN4IoKaYUiT+aXMfcYD9CKGpoT+THPes5MHcZD6wd473JNQQsj0Q7qzzpVsgJn7/MDHHAL7A8egWguYFBo+AOVIb5b2adjybX0em0OC2aNIWGKtMV5//j7s2jJavqPN/P3vtMMdwh7hyRI5BMSYIkM0lOV6UsnxaWz2obmqLFAUtFWSpNQ9sqTWu74FmWPhzKKrRKy+JBOVQprVKCcnNikoRkTKbMBHKIO48RNyLOtPf7Y0dG5s2uhFSpVbX8rRVrxbBjx4lzzv7tvX+/3/f73dJ9AaWuCj6StX2nksnEPNR3LncX1jI/5SMyPqrL47kVq3CUFRTtdULc/gwrE4dUC2RfOxdsHOXjo0MoaRBd7eRX+eRTzd2FtVzUPoG/1ENICPwEAXQvnSepS/6yb5AB1SDCCqFKZSibkJsHBrmzeyNLt7/AYr8LH4nBoIGuQo1eGbL4qiVIZXhhuJttPedzY3FjSz/xyWSK27s38snSep45/gwWJRYld0piJ6AuXBQw/b7TW2jBgwxuw4lN9pUy8xgtSFPBB0sX0d7e4MDuDv6yb5BYCH5SWE+PsA5sQjroOTvxv1zP80cDZ/GfnKXsbZYk/+HAmcyT8kB1D0IYfjT8CLt1he0TL9Kb7WBJWw/XlNYRJYrQaAQwJ6wc1+mvPEHO2HvaAN1pQjGNaNPwUN+5nLl/B6d1LeMiUeCsnhUU0oQrJjbRqLjcVNzI3qRiQ3dC4QaavNH8aPgRpppscVPKOo3vT+zgvaU1NExCXyq4qbiRM1MbQ1+kctxY3IgvXTb2ryKbjZDAgGwwmGaJMfxd+UFqaNY0UjJuQsFITuxcRL8IOD5VuAgebe5uATb2r+KS6a3c9DpJS+nk2B+vYecBu5q8QRFwJzaEe7hdBXzdGDMNLYrkV7V/F475SPtNEj6Tk0dXNHjhzoXTXf7ipUdte4Y3u+D1d1cfPdnxm5y0j74K6dq7xMIk3Wldy47a9owzFyYjP/uWoyezrt167NJNn3Vmj/rZqUeAU95Re/ooLSFoO3Z2uedf5fgO8icftOFXkZY6PK79WjZ/9wvH3HZpcvSE2TvrC6OcPz7n6CN38UkLWdeufhXWun9I9h/j0UHWCY762XMrVh1zP99Uncfcdol7dGmph52F4I+TTOYoLeGbeqEE6EHRiSIR7nIAACAASURBVH/J1jRet4jy/2GvYyhjEXC4ztv+5nuH20nASUKI+4UQDwkh/vC1Ov134ZjdIMUAK3buJC89bu/eyBasw1iWKuYnLcCkiIfCWOSdUqAcsn6MozSPTeyiTwQMJAntjuUgyOUifAMdzT2R8D0cz64AIkwLbSUBKQ1fKG+ikKb8vLCO65/o46/6BhHS4Bq7RQQQwtCXGC7sPYWPl9bzN72Wj7koAkyS0pckLDIOF4w9gjHQ210lFViWunxEXkPgJdxdWEteQ3dieLD3PK4ZHaJdZXjf+BC7V52KBkwCvyisbYUwHF/zqdJGAP7+570EQqE8QwkfF0HGaJTUtONQoHkMzXO8NOgl27zcp6sCi6WtjMhLHyUNi4zLCbki7dLnK+UteG5KQxgyRtvdXKPGdL2K66XcVr6fbWPP4vkJuUyEwuAEKSIX0PXdZ3CDFM9PeHdmCiEMeA6hsDsj4ShygXV8BxNUeA5Zo8lJy4WMFEgHVr38BPkUnDx4HZoPjw3huwl5YxVM3JzGE5IbRoboNyGTl53CptGnyaHoEwE1YYhjReAmqCx0DtRY0j6HEoaMETylZ3EDTY/KcvnkJvq0wnUts5wSxkpCAXkj6EvApJp2FaNce06y2oC0yLxU2+TbwSSxcjVup2WlG0gS3jG9hS9qn8CPKZoI4Tq0p5ol/jwxmu0TL9LRdALLZZ4VJqDX6yDXFvK2gdX0yQyXFM+m08tzatBv1cH75skKC1p3ECjf4AYpdQHLRJ2ChpxI+IPp+8lpe/4fX7yaZ6ZesYlOaQFMYO/PG4c30aEC2jQMN6ZwMppApFxVuohMYCfeZbFhsfEY7F5JimEkmqWER7cWeColh4NrLDtkIBzWyh78wK6qfTehXQYcZywrXbux4RNHaQIjeHHmACXj0pHacb9I1XlC1Ch01jlOWcredv06OWsjjvlxeGlv8/HB3/DXHOBEYCNwGXCbEOJVZ8XfBfl3cpMP4+BjTgjxcSHEF5vcGU8KIf7ptQ4AbNKko5nskAhqUvAm0wFSUBPQsTxESIE00BDS8hY4dqaNEovaA3CxVREnud0s9mooqQmFrQD4RWEtplZvqS8fvLzldSuIhEA2laJ1U6q9amJGlLHbUxaKvuqmtPymcD+z0qprHxSgrEiFxlZeSGWoVnxcY4jrspX5TlLJjLRVD3Up0EZwe/dGss1JSSpDhQSjLcAkbtYfO74m30Q+ucaGv4yGCil/Xb6fGNvXHAnJEYDLB8efa3F9VEiYaIJjJNZB3ji8iaVOOwrBzQODJKmkL7XKG4FQ4Dhs6zmf2ZkMlxUtZDmNJROVLAZBfdrDhBFT711lHZcRhA2HWuJi6hHdqeG80e0gJFrb/5ukEuEoaAoMuFLbeHzGI43g+ZNW2QoKaSepr/cNIgRMipQvDgyShoLjjM/nilZd+6DytI+gQYoCHEe3VJZ1Ihiv5KinllrnnpEnSELJpK7z3Z5BbhgZomtVjBSGWEuqNb95XwkmHDCJJtISIe15e9fUZkxk79nRMINUxl47k9iKmKqhLoUFN2FDIvWGS2IESIFvDLXI5d6xJzm5sLg1GL9Z3kZFaAbcdrxsiicUKYa7hh+lzckwpyOuKF2AMdAwVqk8xBA3y24Oh0xHTecXGHv+ZbMyYrl2aMQOd2RSflpYx/zUwf8qCQWcml9MPC9RGPbrGo3Q5ReFtaRgEZVG4yJY4ndxc3kzwlgmxDlissYew7yOmBMpaSIZU4YwdnCEIgUKwgJgrpwYanGq57yAvSJiwoEJadBGUBQ+81UbRrmncFGrsuh3td9kxXx4aW/z8deHdXUAWHLY68XN9w63/cBdxpjYGPMS8ALWUR/VfpdyueeNMWc2OTHOBmpYaal7gVXGmDOaB/DfXqsv5dpSoVfOPpkXwnGuGh+iPzGYWkqbBt2AtKr5/PAmqrJ5yGGIies4SuMHMR8preXr5a20mZSHa68wHmaoVAMGEk1gNCGCybtGWluTDNJCfGWzdMvVbFcNppTkp4V1rCbPjcObOOHpZ9HCzuqfLw7iOBrfGFI0b/GX0KZpKVMQJ5zbP4YEMm5MGktqkYuvDX57ihDWoUppS5Q6Umgq+lBVgmujDnxjiBuKXjykB5lmCiSel8R12VIVlsBK2YbyDd8sb+O60gYCNEmk6MJtZcMFNm4NVhXjk6X1CzhF/lvitQbrQ9WXkAhuGBlCa0FNQt6k/NPwdogjHKkpdNc4ThzaqnbnrLTTip07Ea6LqSUs3/E88/M+npdaDhhtGHMEOxadhanWSLVEAflshKnUMHFTfil17OQ4bWlbT37haY5PQ3QNGjOKq8fsIDYYrhux1ToFLehKoWEU3bc/y38uXchLps476or5ZuZGScOOhwZIY0lv2zxZJ25RV0Z1h07pU5XwpYFB5l8WPBu2Ezh2sljbdyp7RWxVaByJxCYM/yCxq+nrnullWjfodkKENCSRold4RKED0jqog7Sd4ybCdTQJEhMeCv28u/9c+tx2NPC5ouW6/ovyFk6SbRgNPcInQPL+0hr21ca5b/QpTjIZjBYoIfib3kFGTAPpWuh/dwqTqc+4NIRY9R5fGx4rnUWqJX9cPBtlwHdSLml4eGj8nD2esXSejIHhyIZhhDCskHmy2Yi3TG/j8slN+EjuHtlBzaTkpcdNxY2kAga8OmenGR5R9vrVdUSfcUgSyZkNO6n9avRJ6kKToOk3thxyNvbJGVjZsZRsM/kfILho4mEKRuEHCQ2TYhCkr83wcExmtDjmx2vYI8CJQojjhBAecClw1xFtfoxdLSOE6MGGNva8WqevVyjjTcBuY8wrxph7jDEHA28PYWeQV7U7x4ucGBmWPfo85wSWgOeyyU2oouXN9Zd6qLzkg6WL2LC8zKwC0T+AKp1M77IK7b0Nqk0HdsBxeWl2hB6vzknv8bk3SNEIep0QnUi8Ns3HSuu4pbyZrDYUN+8iEoLT9jzJxZFPT5ry/3qzLQc4MriCM8w8Z+x73JYKOSmvuIJtY89yS3kzHxgf4gfDj3BNaR2dX3uUFTt38qnhITo6Gvj5hB96Pns8iXCs89rnGM7cv4MrJjbxgfEhDNDfV6En0fxf01sJjKa9FPKV8hbcRVkcYejsqVGfdckvN3yhOMgNpQ382diQld8acPhJYT3tRrLXcfEzCTdeac/rfV1ruHRyE/nUOqgxkdiEZWmDdbbA2omHOatsq0L+H29VS1duMgp4XNZ51rMZqW9+5DEuGHuEE55+li+UN/HDrg0kiWVa68/UeKx0FvKE5XT/w3P8orCWJafO0DlQoyvToOt7O7l2ZIiZug+uw0lXZrh0chPtPXU6bt6KGugkQNPuh1wzOkT3PzyHX1K8eOpK3jj1AEYfIq+qxm6rbtbtMDQElqo1kzL9vtP5u/KDFpE2vRWNrQ7p6KjzlultOL6mvafB3crmJT5ZWk/36RE/Hn6Uq8eGuHZkiDQWXD65iVRLolTxJ2KAxcZFA2pJL1/2I+KGw4Xjv+aXhTX8XflB7ht9ikJHjRsnOuk8rsGt5a2sevkJRp5vo10bvtWcGMd1nfZCnbyM+fk/tPOO6S0U++a4Y/hhto7t5JrRIT4zPNSC2O9IJpkeyxGi+Xb5AWom5fQ2myf5zPAQaSy5vfwQu1ybIHQ7YWi8n2FlWBTMc9PwJiRwxcQmHg2sxl8mY//vx0eHOHdkO6EQdHohy3c8z43FjWwd20lNwufVSQgJ09rjq+WtnLbnSXatXMlNxY2cHAn+cOBMskJx1/CjLEkE14wOsTvJ85SyMmfXjwzxzNQrvCmZp7NYY05J+jrn+VbvIBkj+V75IW4a3sSVE0O8ZXobI9LKUlVIUAbGmhQBIYa5SsAdww/zlultLYzA72qvV4y56es+CvwCS+L2fWPMM0KI/ymEuKTZ7BfApBBiJzAEXGeMOTpCjNfPMV8K3PEvvP8+4O7X+vLFZmGi7SCcE/5PRrGl2xcmcerTC1nEDreZXy5k++r/xNlHbXuwhA3g3tEnmf7gG1qvLxz/9YK2o/LYhSH/Q3SIde3l1Se/SstXt/bFh/p53swze9ObW6/fMb1lQduDZXtgOXlfzd50mEzRZUcw4x3OcvbhH7+bNb2ntF7/ydTmBW2XXnQoOXTqCQuTzpP/8ZQFr/fdeYjnau4Lb33V4ztYnvUvWXIYQO8aE6GOK7Ze/+ggj3TTDlafANz0GoP78cWrW8/vYuE99Inw6Pfb5/oXMtEt2XAoKXZH90Z+1eR7AHj71UdfiZ3fu/A+WW6OHd365sNY4r7bM8jbp4+u+HF4onB4w4oFnx3JkvjTwiGtvae9hd7qbufoSMnPyoWJwQ+MLxzPdx3W7+EMe0BL5OBfw3QqjvnxWmaM+bkx5iRjzAkHVZyMMZ81xtzVfG6MMZ80xqw0xpxujLnztfr8nR1zc/l+CfCDI97/71gA3+1H+V4roP7zZBc1KXjx1JXNJJYlaE/H5/nSwCD13TFpTXOC9rize6M96Po86cuPkyaS6oRPFy4fL62n5zAI9ORwjhObGPy5xEPvL1Ofcug3DjcPDDLmCIY3rKBdW9a4f/YaxM3o8y0/7eSv+gYZGNrF1/oHeWqZddRR6LC6CUw5KJL56eJGBszC7PL4VI65iYC2TMiS2BDNSsaH2yhowfbi2a0bfV7C9FS2VbM5oRyqox4fL60nGa9TM4ranE9ckczvFYyJlPNNG9/7ho2hxhP2/35meIj+JKE27/HJ0nouK57PG6ceaMkMDeQLrEgdvtw/yM3lzVxX2sB1pQ2MxXPsWHQWXxwY5A8HzuRN/WdwdWkdOZnwheIgK6KES4vnY17ZyZdo5/HFq/lYaR0b+1fh+QlxrJioZ/DWrETvfhmwk2dt0iEJJfk2O6F8aWCQjJNg6lGLBChuKPT4FEl52gqUNny+0zPI9PtOJyynTSJ4u2o5cJF1HKWuCo3mdlbHokVqM9LIEj35Cqd1LePjpfV0mJgl2qG9s8FJzz/DbhWQhJLKZMD9Pefz5f5B/qK8heoeYVXAm5bGkihWFrzhJMQm5dPDQzQE6JEpNLYC5Z7CRcwIl9GLV/Dp4kYmZ3IkoaJ6wN5vzxx/BslE3ER4akom5GOldcxOZYi0xFRsKOTEZ3eyqM0ClT5XtJPQeneAL/cPstxpJ5uzidJrS+u5Y/hhNIbLSxfwkdJajBFcVjyf00O4sbiReMYef48WPJ60856JIX5RWMt3ewZZ2jzn2gguLZ7P9aUN1Oseea05b3Q7tUmXvBG8s3gOwtjwXBJKXAzXltZTUBF7Rzo5LTSW2c5oOnBY17eSbuFza/8gAyakB5fv9WxscVrcO/okldEAaWD/dDtXli5ktrka/lTJjuX7utbQYazy+pyJWBxrik2yfxdoyx1alLxe5XKvYyjjX8VejxXzW4HHjDGtei4hxJXA24HLzVH0vw8PqP/pgF3pOJ7mr8v342vDtJIIR3DtyBBOznbxjGxw6eQmehKDmZkDP0eSSFJt1Z9TDFPK4ZLi2cxEPvXIbcKeBQqNyPg4vmZYJExLzYQ0uH0KZWx4AWCXb0/JzeXNLXpRZbDwYWw8PHMYFeDX+gd5RTR4UYTMfnojPy+s4/PFQdozIdm2iErdRwHK1+RyYQs+HArJX/VZsqYoUS3RUYVBOpoIja4ZssLCmzPLLGF4n1E8Jeu4xsYsDwaNPlRaywHXTg41NCuxVReFVFN2JafnljApLY3i9aUNvGiqaAxPTb2MEIZQQLvwOF118vXy1laMVQN7k1kIspZxzktxm5OXl01wnJSdnkflh0+B0Ux/aDV7zzmJNLbJTiENMufysrT9yZ4OpLDAlbihkF0dSN9hRkm6sw2unBjCGIMKoD7vUkgtTFoFdvWsU8nXy1u5eWAQ6Ro+2axF7vPq9PzgedpVhlkSYiSxgCSS/Lr/HHLaQqwbocOfu2mrHtzNplTSBj/q2sCXBgZt0k5LwsRpJZW/0j+Ii63KMM3//oRvaYZkIBgTMd2d82Q6Y8K6w/WlDTiORgaCwBgkMIFHhQQhbPJYZHzu6N7I9uLZHJfp420Dq/GMdcC7zDwvqQTVpCrdK0LmmlP3ptGnGUlrPJfO4udiOoRLXQqmRYryQDpWkecD40Pc2j9IiOA9E0MtuPXK3U+REYqTY8nqA4+x31X8srDG3tcGRpMqRsCBpELQmZATCb9OJuhsr9PmRfzJ1GY+VxxkkcpZelmhODl1qQlQwixIOq/rW8lVpYuIQodQCrr8BpM6bMHIv1DexIRycIRGAr6wlAxVKbl+ZIj52GWXaKBT0Uo4+68X7ac59se/hb0ejvkyDgtjNGv0/itwiTHm6IWbh1kaS6rSrqAOooVCCaah+WRpPeG0BA2dWMcTC8BohHItq5kwXFm6kK+Wt+Ibw1RaI6esekYoLXfCm6cfYPKOPRht2dYSDMVU0POD51snITIpx0f2Sry/tKYF+plUVp/uy/2DnLbnSXZ79huduExKQ9Uk7AhH6Pj8JtbdvhE4BCL5qmt/HyPw/JRU2GRUinX4NWmh22B3CTUpLNcEBpkVvHHqAcvb0NAoXxNiy+MSwBWyVWVSI+XDY0N4fsLnzx9rwcn3uZJCah2sg2BCGsaIaRMuleZg19oO7Ccbw7zSvGRRqshquGR6KwWVAddj7cTD6FQwRcwL82XCeZfpaoYVUWKPw/dAH9rmjg63o1OJDhOySDwnhThmycUpjeaBG61BCjpTTaXh8b2ejZhagvQsXzCADEBHWA6VRPKh0lq7W6gpyibkpuJGDvLpZ6XHmLbJp3mhW+jLt12bwQ00bW0h1zcBEQAmFSxyO3jX1GauHRmiY1GDe5wsSmqy2YiqDqlIS7YjXEXDKMKqw4TU+EZz9fYCKbYsz2jwMwmBES0Bh6oUzChJxmhyzfs3QoKUJALmQp9yOMMJMo9vYITIQq5JmDcJnUsaDOBxW/l+VnYtbd6nCStUO0mo+GZ5G+8bHyLBkIaWk7nc3LxdMzqEi+Fvegc597CQmgRecDWPL15NXsOMcFGuRQzmlc+0BCUkOoF54zAczfCVRhuO0mzuuhAFTOoGeSSp0bhYPpgZ7ZIxkk1exCdGh9g6tpN2FJl8RIpdgEzrOimG/1A8ly8ODFKX1qGPSU3FxORQ7GsCbX4auLThoI3gidCGaF432s/f5xVzk3/5YuAfD3v7a0AbcG+zjO6bv8tvvJY5zrHHe7v/43Gvy29e/xvcHP+FY4eRHhm3/W2t55+OHUzxb2Gv3PMqmvVH2NP+b0Dl9ypWu/fFY2775rh+zG2/uurYWetezbZFxy422qeODqr617KPqaMDTI6085Jjj4m/mn2pvOW1G/2W9nvtmI0x88aYbmPM7GHvrTDGLDlYSmeM+dBr9XPS888wIQ1R6OBKh2lH8NXoRdKqrZU0RpDMC8ZMxHd7BplUAhMlmKhOpRowNZtFIPhIaS2REKTGcEAHxEYwL2wp2k8K6zGzc9TnPD5SsqKiw8pw4KIVTCvFQ3225G3MsRfif506ZlfmWD7n+YaFcD/Udy639g9ySmEJXylvoVsLFosMf64HmP7IWWz/01+ygypRqpibzhD4CTUpqE27VGYDxqVmpm4h4mMOxECiJVNNBFRN0FKRjsbh+10bSFLJ7G6XmeEs4yLhrFBw6eAwf1d+kHhe8pHS2paCSaVqB8VHSmu5r2sNOQ17XMNsasMfEyIhg2RcN6zyieMxXs8yj6bNyTCtbbKmkSoq0v7+rnAc5uc4v/dk0mZNcLk6RVh3SIxkVip0LEj3jaNnQ5Zuf4HKbEA+G/L8eIF0xkbuZxoBaXma4fkc81IyVwkwMxXSyQbzUnKAgCsmNqFrKdG0wFGaNg3z+x2iqmJa2evgInhOhuhEoDFMC810aP/3r0afZInMkSJwjGB2PiDWku2PF6nPuoR1h9nYZ1po/mjgLGrTHg/P7QZsGGFuOMAA86nL8HSe4cYUnxm21TPxAcsZoVNBFc0rrkM0KynrOuW5NmZGstQqHrUmkCMatzsix8CsVFwWRUzWAkvBMGIduiM0GWUTivtUShbF5aULWIzP3mSOmX0Bc6RcUbqAM/wi3Zk2pnWDiklo1Fz+uHg2X+8bpEJCXJfMjNsQ1m29gzbujGBWwtYms+LmrguZMhG7TY1qw6Oi7IIgrDoMy5SReI6q0Gwd28n8hI8G1mSXMTmfYbIW8IIKGBEJVR3xhJ7Fl06Ld6QmFQ/qqQVcHZPEVOcCEmFFh0eiWW4r30/VJFw3MsSYMoxpnw4jmU7tvdemrb7nd3oGcRDEiWKxV+DOI2Tcfhd7PZN//xr27wL59+SSM+kwAtkk9YmBT7onIrOCNiNJQol0LcG9Yww1iQUmNGuaPZXyUjpHgsEzhrz0cDHknITrR4aQxhLOA0ilEViqxjYjUIEdOJ6TEmJjXT8vrOPmZ0v0ttREwHVSskh8NyUWlkvgI6W1uAamiK0MjiMZnHqQZSKDAFw3pVrzyGuD41lUnmMEEsueNZDY5AZYAMDG/lXktaVB7MLB7bCq0VIY3IxF03lIvqHG+M5mG5eXjqFKSh7Fd3sGcZTmitIFfKO8DUdoXANZI6ikdWakJkbzjfI2csLFQ3JO1wlkZILGkBUuY/GcTdSptBUOWex1gRfwvxKbpFIIju+wv6+NTdA5GYMQAqRNfGkjbDkdIANJhLFhmYxLVqR4xtDR0UD4HsKT5JshkBuLG0GCdA2rDzyGAbxcitECx9iwT79xWtSax4sMK1JFA8nY21Zwcf8ZxFhFEx/LFKeaddqOnzIxn+Ut09v4SnkLfTLAzyecmrcVnTkjSVOBADyRkiIZqdpKiw5t/0fQ5KRQ2DI96WocBJ5IkUqTppIGGtdLEcqQ1Xabf9nkJtZOPExXpoEDiMClIQSTxqNd2brwglHkUCgEeSN4ePx5Ww+NrZBJ0XT57fTLLG3CsbkHHJbECdVmsiGTjZvXCKs8LWwo6yDoxJH2eH8w/AgC8JuRJ+lo/qK8hS4nh28Ey9r7yXTExEIQGd06h1pAu1H0qCxtwmU2bTQl3aBLxwyobCuP8sb+01lsfDKZyIbwMBzn93BV6SLOkO28q3guPalAI1DGkjm5SBzAMwKFoUKKozQS8TpVMFszRhzz49/C/l04Zm0E41JjjMAXCi1gRlr5l08PD6Fc3aonTIS9iJbHV7e+v2n06aZCLzw29xKBseizG0obqDfjzC/dbuOnpnnBq8JWS4RCUA0tlSVY/L4E/mxsiBdPXclLKiVJrUR8kkompU2aPZNM82djQ4ylNQanDoE2/qK8hfnUIYosKrEqBXFD0Ygc8kYQGolrYLsbMyebmfLJTVyZ9rLb1XS019mpK8Szgju7N1INPasSXfVIMUjs+Xp38TySUDJvbH3yAdfGiwu4XFo8n/WTDzEvbejl+WnLxXBwRfaj4Uf4SnkL28aepaEVRePyfK1MVvpcOzLEfOrw/uaA+9XokxA1SJE4jq2p3TM7bPX8EPb8jdoVWfcdz1mmPi8hk4l4MnCo7JItZCdSopoIv0rFx4QRaTVhjyfJak3GCIQUJHXJk0vOJGsgmldIx9jnqeJZUecr/YMkkaJMxEdHh6hIhUlgPKlSa4IRqkLjKM106pEiiGoOPbka93Wt4drSemIMYdWhqPLcMjCIi6CtO+SiiYcZET4NJCs6S1xf2sCYMuiGvd+MhhWpw9f7Bvnwng4K0seVmjSR5NpCG3OObMz5A+NDOAa+1TvIJcWzmahnCIXAJJpQQicxj0weCrN8pbyF7Y0DTIiU/lwnytXMknB56QJ+MPwIL84cYE8yg2yqR+9PK+z2HEoig5AQhQrXwMmmRlkmhNI6OL/p1eZSlx8MP8KlxfMJteJnzhx3dG8kbji8t7SGvY1JImFwpSKqKVxjyAlFQyvePP0A3YkmFIYn6gf4wfAjPDH9koVmi4SKcBhO53mkyZ1x3+hTPE2FmbkMz6qEBpJO6ZNguKW8mS7hUUpSalJw/cgQq3tOIMVOZgroSRNSDDN1n9ho5uXr5yR/b4nyAYQQn2jyiz4thLhDCBEIIT7a5CU1TZTLa1o2F9FuJKfteRJHKM6KGvzSTCKk1exzsymqKXrhGcPi2IA2iGwHbflGK3sOUJOCyXqFt05vY9V7FYtTSdr8o9lchHJ1Cz6dMYKl219AAFs8u2rxNWS1ZtiE3Npvmd4Wp8oStJOQarua6cm2E5uUzxcHuXf0Sd5ZPIfOW7fzvZ6NfKi0ljoKR2m+IZvZe2XI50MKGrqCBqmA/29qB+0aMm7C97s24BrDSbF1fgBOziCNIe9HPL+vh0KxRophbzhJCnx/+NdUJgPSZpryIPvdjevG6RPWUea13aK3+zZc8dXyVl6IpzilsISPl9Yz1HUhWZVQEZpi0MX2iRe5obSBNidmTDcIhaCU74KOHlyhSRLLNreh7zSCIKbTC8lpbbd8UjB5+am4QYofJChX8662cTrOkHQ3Y3XCU5x2Sa1Vnyx7OnH6AlZEKW0i4ZLcBKrgo3zNGfsepxgn5EoJUpnWqq8XjylpyLRHrYRwr45xOh0WuR10CQ8Hy2fRW6zw9umtDP4XC5kOY4d2P6SBoa353T3xNEtjQ4jB79bcMjDIIhoEaHbNlLmlvJnACHQD/i4QeNmEPSrl6rEh9sezKATtmZAgGyMEnKBdPD+hvLuTr/cN4htDe2ppZXuzdd45tQWSlIFYUzEOb+k7g//bXUJV2Ot4kt9LgqHNzeI4mtvLDzGu67yriTDNS582FEEQc4pTYEmsaZAileHv404McNHEw2SQZLUVlji+CTTsDeq8sf90Fgmft1ce5Z1xO5dNbiKOFH9bfoBer53+VKKExM8nuBiejaeYki5DXReyz5U8nk4zHVZ4d/E8Lug+iZU6oKQdGkKwSnXiYRO0B0m52tsaLNUOPSrkB8OPkEVxWfF82lDMScUy0+Bz18O+uwAAIABJREFUxUF2TOxmxNSZVnDj8Cb+KWP5pjuCkAGVpS9JXj92OSOO+fFvYb8LV8Yi4BrgHGPMKuwkdylwP/Bm+O11iB72js6edaTNVY7edud3Fibe+i/pOGrbtxwBcvnz448OzHF/gz3V4XL3R9oNnecteP2Z5Pmjtj1j5ciC1//9T46ejHn3pqODII6096UvHfWz88TC8/XGqQeO2tbPH3uSc+ddR5eWOpJdbq937IlCd9XR2QP/8cvHLrG0Ojx623fXFw6Zn7+KytOSUxeyy30ud/Sk4v9Oysd2cFjFmqPZfw4Wglyy5ujJ8W29px3zby5/leTfkZUSa6Kj338b+hb+5tSr5HbfVf/Xc4q/76EMB8gIIRwgC5SNMTuMMS//Jp0IaWhvbhnG4jmyBnpkBtXj05uA2w7SE1xf2kBWa7p0YkMZWDl6IQ45P9fAmt5T+EVhLa6TEmgIDBRlA/JZVNOrBkiKTV/SmabkciFvHVhNXhv6iVh0/y4yGl56wym0acgEMZ04dLbX6UyhL+gkr/wWMvEgxLknTejC4R3TW8gXGhR758hpy8WhlCGfGowRLI9julPoSA1OM7auhKQj1QRtMd3SJrMU4HkpbifI5mp/kV/gf/4wy7uL59Fzwjw54fLJ0np+WVhDJhOxUnXQaxyeWvYGutOEU2NFX6aTHnNoFEghUMCKoA/fSQkxGGM5r3NGkvFjPjM8RNZoTszaePJQ14V4fsLJso2lThvKtaGCLmJ0IpCFPDLn4WVTHD8lrLtEoUJkXLoTw5buCxAZn7ZMyFXjQ/heAkIi2wJcY/Blyt/0DmJSjdP03crYUjk3p7luZIiMm3B8qsgZgd+tGWmSMRX8kPi5ffxsZAcBAomhR0tqc9ZJBMaQ6bDLxmw2ogNFGxIvm9DlZOnUVo5LeIK+XI22IMJrAiG+2zNIV2rL9tpVjJdN6TaKuwtrcTolDgLHS/FzCV42oSxT/EyCardgKdcYAqO5udaGEJZQS3Rk8Yy2uRDhkpMe/emh4ZhB0uu2k++x/89FskJkWdFZoqIbZIwg2xkRYkmMAhRehybXYXdld3Rv5BXTIEWwKLH/e3vxbPK5kMgkHJcqcvmIXDMceLC6qejkbU27k8XtMORVzAPjz9GWD61or4YYzcn5RWSFYm/DLmCyBjq0rXEXwGLjstzrYonIksnHLI0NbZmQdunTIKVXeOSN5BOjQ+T9yBKTASeKPFltgSR5FXOS9shm7UTZIRI6Xqcqid/bqoymMsmfA3uBYWDWGHPPb9OXcjXjzXDE+cFiNLCtuptkrMErjqE+pkjmbFwqFIIXPRcaoY17xpLxRqaF3ppW1sENK5f50OMD40P4xm7tiBOSsMnAheZBz96wiRCs3P0UBsNWP6HWdGBXjQ8RNxQHHMPprzxBt1EIaZ3/zqm9LJE5vlActLJSwOx1a3jr9Da+UN7EPYWLiBsOB8bbLYNcKkgSyQsevBTleMv0NqoSXnYFqw88xrunNmMwPOkL0ljynfKDCMeCY6JIEY5LKqMBV5UuYiKusjy1SaL6hINCME7EuPSoVAO+Wt7KZ4aHCCOHmpBMKsirgFmhuaG0gbPdPk72+9hnGtw7+iTnjmynYBQDbjtbay/zmeEhpmoZvjgwyDuntvDE3MswP8fg1IMYI5gm4ZlookXSNCw8vHxCsn8KtCGqKSZG8wDsm2snHa/zCz9k3Pjo2RpRovhpYR1pKtHjU0S7Z4ibDH+xANNIQVpo9IfHhogrssWcNh367FQxp4UJjQlFVzNkMxt6pDP2en6pvAWNYEJqpDBs7rqQhhDUZ12qkcvlszWyRvC8mSduKLpEwFubPAwvPdTBVC3DcC1HzrX9vWdiiFEHhBTMpw4T+/PsESHzQhGOaR4Jh5mYyVGf8yjv7WiVeaVVw5hqsgAieCmZ48z9O6gKBWHMrFK8dXobY7rWBFbY8TCnIwSw2u2hPmPTwz8b2cEt5c3sminjC5eq0DQqts73htIGaqTMjzpUpwNecFJ2eYJlIuBlz2GP67LD08yH9v7oUlleUZqJqRw/CcLWGPzSwCDTaYOsgUfGX2Bur8dk6nFl6ULmKgHDtRyOgRNUOyPRLG04nJoZ4I+LZzMmLZBmr6kz4lgqhZeiSTwElamAV1zB/mpbSybr1vJWJkTCnd0beSC1km6re07gKT1LVUJNGLY5WcakptFwub38EBumHnzdpKV+b6syhBAFLFP/cUAJyAkh/vQ3+H4Lkv39yr4Wf8Hflh+gNzEMtp2IDCR9WtiVWac9QYHRFFIDgV1ROl7Kko4KFzi9ACyNNanRXDkxRM63M20+1WzrOZ/RH4wTdMS8v7SGFanDidpl9C0rkM187z+PPM660OGt09u4prSOWwasrPuyWPDUsjeQ1xYB2JcmnNi5iG+XH+BTw0NkhMO1pfV0fPGBFv9Asd3yBxSyDbLa4Pga101ZnAiO8+a5o3sjCjg+Mi1OgK+L46kIjXSs4KnMKzp0QjYboVNB0BZzW/l+viGWEAuYMxGZnoQuXHI4dOkER9kY6U3FjYSxQyoEvoHHJ/dQ1Ir+VJJDkhcO3x/+NVu6L+DxxasJEMymDXbN2C11mxdx3cgQ9xQuYkW+BFJyV2Ednp8QYfmvs50RShg6dMqi+3fhLOvFpFYAtb2tQaFUIyMSRFZxkgk4MTeLyPm0tzdwMQRBjGjP4/RZyK6jND2JRmSbIrap5L6uNRY96Gpu7R+kJ1PnRO1SkYpM32ECucLQ97NdgIU2O8KgMZyy62nagpATqZHpiFm2eJpb0gEWx3AmeTIdMffO7OR7PRsBWHbmDKPCo+CEZIKY07qW8aWBQUoJyHaH3mydju46HTgERvPhPR28x1lGYiSOl7L4+Bl+2LUBN0hRWUExgbzRvGN6C9Npjft7zqdfNsB16GlKJWWEyyKZpSeFa0rruG/0KW4ub+Yb5W2kieSGkuX9eG9pDef3nowSgr8ob0G5mr16nuMSSR5Ftjsh2x7SqxVdqUXJFWPNijimyyg2TD3IuSPbuWv4UdqNTcImxk5c2a4IaaCk8rgG3l08DzdI6VIRWRSpsXS4HTrlRO2zPOihRkqK4cfDj9KtBQUnZEAEzDYXWTun9tpKk46Q4yNNRiRcUjyb5cZnXd9KvlHehmsMS6PEVnvIgF4ZsCzS3FLezHlRgwZ2cv14aT33FC46VvfymvZ7G2PGxpFfMsaMG2NiLMhkzbF++XBI9k+qS7i2tJ7HF6/mncVzuHxyE2/QAWlVc5+cY37KJxyFq0oXcXLvNJNK0H7d/8aEVeYqAXGsaBwmzhU0FXVPeKt1zDUpGdc+cayojAYc0DWy2q5kqgdcDriKr/UPcnH/GezyBHcX1nJreSvDMiVu2NXz3HzANaNDlEfb2ZZRzCd1LimeTXemje8P/7q1SvrnSi8fKq3FaEGl4nNL6lGRgsnhHL+a7mPEgUrkcdnkJr4avsAuD4ajLH/TO0hVKAQwP+OxO62QTKRMKIdGw+XFPd1UpwPeX1rDbX5KTdjjjyuS02LFjImZkg5hrHjfufu5cXgTiZZ4xrQGSlUYrnzHFHOkjKQ13l9aYys3Gh4NDFeKQyRAU2HAx0vrmZIu2ydehDjikumtVOcCXASfLm5kaiRHI1U8GigeX7waU62h5yJ27O8njhWT+3I0jOIP70kZEQnzDQ8zH9KxPGSf4xKFDumeYZKRBi95imeSNgZkg2SsQW3E4ZzhRzkgPaYO5AgrDo+pBhP1DA+JKnf7IbUR1eKYnsJl5E0reNvAaqpCExpJ2YQ8MnAOU/WAVR9rozbjMTeV4ct+jec8zT8nI9SmPSbrFa6Y2MQnS+up7PMYcQTTic/sfMBSr4s70wNUJXTf/iyrDzzG5JgFeLx9eiv74hlGlMYRmmsns8yNB/ytN8fMaJbt2/o54MK0VNzWO0hBZfGclJnU43/8g89+x2Vz14XcPbKDGM0rjubW8lbeXTyPq0vruLj/DOarHs8ZO8nvT6s8PP48w9Es7y+toVFzWyvQGim1SYevT/RRE4ZTk5A5oYmFsMx6Bi4tns+2nvP54sAgMyLlg+kET4ej7JU+P35xCZ8YHeLZaJydTsL3h3/NWLmNudRjn65RbqrZTChbNQWwN60yndb5QnGQfSrlMZHjq+WtPJBO8IUm78e5jZjZqQzjjmQcjzfqdkZEwtaxnVxRuoCnfUEsJM+IOm9WfYRGM+lIPlXayN8HluZzYj7LJBFldey5k9f2P7+/Mea9wAVCiKwQQmCpP5/9bTq6LbcQKXRQ5+tfsq3Tvcfc7+67F17Ixe/Kt54/4S5MVh3UKztoI286xLY1c0SC4nAVhRs6FjJgHbnVuvowxaXzj5Bx+mBw0oLX7zoM+Xc4ExnA8uLCRNKfnXVIzebH6ogk06MDrecHjpBm+q8/zXM0+7OxV98mnt61vPX8n+OFXOBdA4eSQ6d1LUyc/nzNwgTozkcOXUORcRd8tkMtTAyWnUPn+nAeaYCotjAx6J/Ydui5WFjnNPWPh6SbrgkXIueOTEidHB26N/aE4ws+O5wNDeDHyw4dwxeyC5OGZ5y6UA7sa5lDbW/844WMbLePbW89n9QLGdkOV38H6HIOHf81pYXH894jJNKcw8geDlK6HrS/FH2t54NtC1n0BvIL5b86zaFz8qkjGB93i3DB6z8Sh67vTzMLHdvPxUKk5OE0nlvNws/eeBiT371zR0+M/zb2e8uVYYx5GPgh8BjwVLOvvxZCXCOE2I/lYX5SCPGtY+kvxiCF4Z+Gt3PDiI0LC2lvSi+TIJRhRNeRwAGlLe2ltHXCcSLRwB8MvIFYCO4bfYq/6htkpuFz88AgsbBKwKbJ6VAQPg10k2zdkE8tqGO+GdubkQ4Dv7Lb4lN2PU2teZY+VFpLthmXLlenuGv4Ua47LCM989Gz+UVhLd8sb2OsmiWTiW2/EoKM/d6MSFHNVZ5voJQI3jG9hUllC/K/VN5CEtlyIp1YLt2DRPaen/Dt8gNcpLN867ElOE1CnUA43Dn8MJOOQEnDfJMD4yA5UVWY1kATwLhpMKCyfLv8AKcUljCXutSERslDt0OKIIvEMYYTOxeB0Tw19TJxYlGDOenRiBwyTsKq0JDGEtMkdzpl19MYLQhjh5pQCEeQQXLh+K/RlQYVY+vEtREIz0FHMKI0HTptEUdJ59CIyLZFOJ4VKjAIziDPxZGPTgXjTTHWwGjCFytEJuV5U2UKlxkTkc1GeFLz1N5e3CAhihWBSKmhWe50oFPBi7VhvtRcDGQK1rmGQjCXenQ6OVY4BcrNBK1BkM+FjJiQ23ptqOtpPYenUotQjRTHy3xLiizFIk+vGh/iPfPz1CIXCZh6RJs2CGFY03sKb+t9A3kjubx0AaGJkdjqC0dpPlJay8X9Z3Bvc7J+bGYP3y5bDpVfNl4h0DCmG0hlOTvmhWYCFx/BnLIitoXmPBVpxXUjQ/hI5lKXP/WO44qJTShluLq0jrmkThZJolMKXTUSIC9cApky1HUhVWlRpbvqo3TLDA+PP08DTd5IehNtRYmFoYGhJ9vOhInwPAvK6jAps2mDA6ZGf66Tdlxu6x3ENZoTTMA9I08woetUpR0bl09ussRPGFbmFnPlxOsTX4bf71AGxpgbjTGnGGNWGWOuMMaExphbjTGLjTGOMaZkjPnAa/UTx8o6Ae9QzDDBFnd/trgR5WqEtDdICiw5KEmkbfvJKGDENLhn5AkaTYTf8tii8QJjCZHy2rSqxbOHlRtJZVpbs/8ki2TMIV7igxp5MYbJ1KMDhTGCvdI62Q81od2t85Fo1txma007g5AodGgYRcbYrZPrWnIiT9njdo0l5rm/xzJnPVl5hRtKG4gSxR3DDyObC6xUNwl/jIWdf3R0CGVobWO95nH2xRpj4NvlB7iidAGJsQxrXyxvxhjDrLAb/5LIUG7uEJ6b3sdbp7dZEpzDCIgEBmls8tGTh8A8Uhp+NrKDjHSJUns+UuC4J56zX9Tw9PI3IJUh8GNcozGRBfRsbnIit4mEUEAUK0yicTolJ8SShmgqtBxW2F9KbEWLTm2Fg8DGjve4ViuyQ7jcMDJEikAGlmayTwT8ydRmjpd5HEeTNgfXzESWwEsYnHqQW8tb6Rc+QtpJ9tqRIbLGkkKFQqCMwSPFFZJ+4XNz2e5mFIZUSzqFi2dsdr9dHFrZRYkiQLag658ZHiKfWif92MQulNTUhLQoSayclisU8yYmxrA3mcMTDh6Cn43saAGb7j1sB1WJbNldEik6VZb3TAy1Qjqum5IzEi0EBS3JaMNAkrboBRyhOb1rOVVSApG2qiGEMBSMotdrxzeCidqcZdoTgqQZ5x2cehAX+EZ5G0XfTvRn9aygA4e6sMm/fhEQCavQM1GbIy+sgokEFJqik6eiY4pBF2OmQWTBoowJuyL3hEWLtmvBD7s2MKVD2vyIfpltCQ68Hvb7HMp43axnUZVSKsl12tXKzQODfHx0CKfToT+1ZVFOHu4YfpjFSWxRTEIiuhax6MQZFuWr/Gj4ET5SWktdwsqupRS8Bt25OnkNbSnkdcrcA3PkukLmTNyirswOpAwkCYVcndv1MAOxYajrQt5bWkOHFuy/4ERcBCuLkygEgR9zXuRycf8ZHNC1Fofux0rrkF1t3HeV3XaeM/wobR0NNmccehJNW1eDIBtzeuygpOYnhfVMNKXgUyM4NUz4jv8Gbi5vptBds/0FVozVcVLaFkUEbTHHaZcNfacxKw1/NHAWjYqDL2QLpRd4CVNXrERhmemOa7LlCSFwETZ5WN7WCpUMdV3IY6WzyCJZ03sKV5fWcXVpHYvbKxRTwWWTmxhwO6Bgt709A1XeVTyXybTG4kUztLc16MdeN9meQ3Z6tPfUybaHKEfTpSKcYpZOHDZMPYizpIfVV6QsihM6O+uo5UVUh09fkrLCrXJ790bcYobsgJ28MtrQdrwm6Ey5dmSIgbwVjBpIBUFHTBsOnysOUlAR7qIcF/aeQhbFfV1r6DEK5WgClbLxsz30L6/g+Qlf7h/kK/2DFIwk1xXyzuI53Ndl0yPegAU9dMqYQKVMxFW+Ut7Ct3oHmfgPJ9OpIgqL/n/23jxarqrO+/7sfaaa7607VyUhBBIIMUwhgQQy3KstCq22tILy8tJCO7b62ti2j7QLZNHaPNI8tj6oLe3Qaist3TSPIw4gfW9IQhICAQIkAQIEklTdue5Q4xn2fv/YdSsJy0hocNnL9fzWOuvWsO+pqnP22Wfv3+87VFkZOGSjkHc9L/lBcTt+ZJHuqNOerfE63zAA3W4jC9ulzKBzRucispka75zciEiZ9N2asQdps2KsFO3EtWDT6G46ZYwII5uZaTdpjavzR5dvPpFfT3tvleWOocmnhUu8JyKVrXNCKFganzYehiokrUMURng+HfNptxN4SDqTtZb35dwE5QQ7wwmheTW7qE6n8Fkg4gTNyUFFGOXFLitBXFjMd9qwEcyLJPPtahMhZK7ReelOhlWNdHudtgjiVsSPig9zspXmjd4C7izu4COjg+TjFXJNPfMlMk1nCB8fGWSXJzhVprGkpkMYhNXNvyXN+UoiUuK4t99H/LcYmF9N5DftO+62bW89NgHhlYTzChJPlzull2/UjK96x3aCeCXx/9x7/EWSW73g5Ru9xvHcncdPRpmyXpsuet9nf6uTz1FxmjX78o2a8ePVx69u+NviKY5fve1tuWM78fyuoj3eePlGzThBvzZFuje9ApW/Vxr/d8Z8HBHUJaNSEzaMUWRWYfKJSvOR0UFU3SxtP5XfQFVYrWUZTbiRH5rUhItsYYzPHXmISJnnZUnLYidsSGwkVSI+mxvAytiUpNGxsIWkKgUDk1u5ackoJakIakZ7oDrrclNhCCFgyhI8WTmIEILri4O8LXcOXy5sou2m+6kdkadVkaDh20QYrWmtDPg+5oaUpaSBNgJKVsR+1yYhbL7SO4CKmqaTEt5U2kwUSYJZgQoFVWGMYP/6DaPMah83EVHXCqs594mU5BSZpr0pj2Q1byKWkMSbnWxOdPxj+XW8EEzRCGw+X9hITQeM6QazhIShRSSMoNMhv9Q61lFglvY7xp6mOuNRqbhM6WYBL4oQwtDcK9MelYpncnShOmyiqQ1sUCOwvQiURkeKmpSEkcF5q1pAVDUu2RqMS3YztTFb84hrQU1AWLdIIukLoRw5yHndbB3bi4+ihEO9Kf5UCj3WDQwjLE0YWlzcNsak1NxQHMKvWuxrjNPQh89b0EzR2FKxt3TAmPBqsLqTCMAvW+xzFFV5JGFHE/qSWsVhl2vcV6KyxtIwKW3+o2MDt6cyzJY9o3RYbqAxYlY/KT7MM/5Ea/aqgDF8aipASM03CluYaBJpFqS70FqT0dK4rTTRSI4wlPHZyRhVadJEN+UGiMsQH4vHLd84qNc8No3uJqslxXKqdS1pbVJ2AkEkTL0DYEYZv8NICXbmV9CuoA0bV1gMqxo/KT5MhQhHm77nIOiLBArIeR0skkmCulEGDOdm3URMEfJX+fV8qXeARmAzLRQL0l2M68MF1IayjDCZFzKq6/w6e37LkefVxh90jlkI8ZdNnYwnhRDXNF/rEELcK4R4pvk3+3L78as2CYzQT1WHfHB0kK16CpTmC30DqBC0Dy/qOuO2JKZABwHUKy3Lp0/lN/Clwv2klOay3LkMdqyh0nBailQ/6Oyn7YZfIy1NWtj04VIT2hh/ao0QsGl0N+8fG+QX2bXkNu7j84WNLHpsL/lAc8aBR7kx14/WkFGaQnmSk0SS2zv78ZqHcfqT57PYneXGXD+PzFth4HkNFyUEtmdEmp5zNLM18x+5SBjxdyXJBUbZri9Q1MouDRThDPw4ux4pNMLSCKmpCc3m0T38yz299MgETiLCFZIEFoEQLRZkHcWOvpVEQvD5vgFK9TIxBNc0LYquyK+mT9v02mkcO+LGXD+9dppu4XGKjlH3TYGuJiR7SwegVmZL13lEgaSozfLa9Qxu+nnXDFBaKVQjbPYNw5asKRvVMG4cP+jsR03MUm84/EnpfqozHrpcQc0EpFRELbKZHwqEbXK9pz79BAKovgBRQ/C1ngEyyToWRk5TWpp2JXl/00cu3HuQS3Ir+cfCZjRQw5AwOpw6uwa7qJUcVGRgjA2hTbrI0nQ7aaal+b1TTxpdFFseHgHm6pB6tk6kDelgUShJqQhV17yx9wwO6jhRIHE9w35TURPPiPnzzsmNXO/baC1wURAzN7O/GB1kSfs8bGFuhJ/J9ZMWNmls5jsZamWXq/Pn4yF5d+48DsyOMxyVzU2lZrf0PtLYLaF8S5ub/6eLg5SVw4Rl0d9wqIUmnfT+vMED9yYr9IXGTSaWDklpQU2b/H/Bn6IyYpNu5n7DSLKisLPl6h6hOVWmWdG1mPnaxZ+TyNWSVKS5sTjEfCdDu7YIQ4tsZJTtzu9eyu2FbQQYNbu+UDMRenRoixPjPXQIl6B5HBpaUiFqse+mhcNHXgY5dLyhX8H2+4hXQzBZDrwfOBc4E3iLEGIxcC1wn9Z6CXBf8/lvjdJ0gjqaqZk4RX+aG3P9LJcZGsOKZ2RAY9ZmdtjlBBHjg6ODHLI1wnHQQY3pSowwkrzQHCxKluDfiw/ymBNjWMV4wPUJBExagh19K5kaSRCgGcZvYZ+HHclkI8aGntdxS98A45bNZblzua4pmPJ4U5rroAgoleMMNyFcu6ISV0wMcWdxBwDR+AybVYYbikPsr6UYmUoxhUPRFlSmXArjaeooZiKHSUuw31a8aCuqkc1zrmSDSrHXk5xx4FEmtY9WphA1Wk4wOxKjXIoxSci8dCclqZnVAeP7UzwXTrFbTXP5xBAzNY8aitsKmyk24hx0jC9eNWgwLQyF+W25c9gXlBjSk1ztZ6g0XG4oDnHAL/HVwiauKw5yKIqzyzLOE6u6T4HpEheMb2diMklFB5zddTITk0nGagls4MWVpxA+N0k4GvDo/LOZrXhUaw5JK6C+P2CKkIIjULM+kw2DiR2dSaKmygSTiv2uzSHpUrA1qhpSGXN4sHcldWkQGpVJj/224uBMmnGpKAnF+KFUqxBbFZJgOOSHxYe4LHcu33SnmSEk8C1GgxgL8yUzi6+7fF+YmW8CSWXaMypoLvhCMzmR4AEryYs6zmhgvud9eoKH3ZDacz6j2mN6IsF9VoWibXPl40nuHdmFpxVTpQTjk0luLmxkYjJJfcpiRsKwY/rLY9VDzIYORdtBlao0hOCe7AU8M3WIh8afYUJE/G1xiO8UtnJbYTN76iP4vkVNR9xZ3MHz4RSd8TQ7xp7mjM5FVMouDwdj3Nw3wHOqTLXk4jdsnrEj7ojaeW/+fIZtM3DvcWFgciu/yK7l2WiGgyKgWEmy3xEccmxKxQRVodlTH6YkNVNBmXIpRkF4jOHzfJTk59l1vG9skIJuMBZWGMNnJqxyY3GIsoTniHNQNLiiWTz/UfFhRkXI5GycQw4UVYwHxvby1r4VTKgGl+fO45AjeEtpExGa52oj7ImmGLHhb4tD+Ei+VXiAiZkEdxZ3UHQMvvm1iD/kGfNpwHatdbVp4b0R+FMMG/C7zTbfBd7+cjuaCD2SWrB6dAePT+7nhuIQqWaF/LbCZoK6jZuIuLlZGW8I0NMzUJ1l7fj2VpUcYLy5ulwVVYlpo+jlaYgENEILpQXDTeuhB8MxU9zTJmXgCouS1CjM4D4izEU/V5Gf1SFaixZE7j9HHj8Kc62m/BaOOakjEnbAJZP3GwKCrYjbIQ5Gj/mQrXEQVDE+co6Gj44Mcl1x8LA7sBY8GhO4UvHEZCe2HfH1whYOzU4wKxRd0iOR9tk8uodOEeOOzn58JfnMfIO9rUiL6hE6IrvVLLPax0Hy+NR+PCwum9zIhqZk6ZOTRnfqI/l1NITg64UtXDa5kR1jhx1RJkKPThHDFTaBMvrEnoLxQgor66FDIz0oB06uAAAgAElEQVSajPnE3JBqZON2CSwE50cVVDXizBXD3Jjrx5MR1AN0k+zTEII/Cmr4o8oUo7SgLdLMjMWolF06lGRS2txc2Eifkth2xHOqzDX59aR12JIendUB7/PbqOgQx43whWRXobtl9/WWWsjnCxtJaEHgmw5jYbwS29rqjEmjTDdnkRug6NE287bsoyYFWsO+YJKahHuGH+Oq/BoWeBX80CLhBS20zq79PTwvA+YFms/mBnh+epgLS0aaVrgWIzY4R+CtIzDQxGY8VTrISC3Rwh9vH3uKDi8DQN5pQ2lBUrq4GmYi441XadpxnVPXdOBQEzBtCeZFgp9k1xnz0xEjFPWBcC89TduxSMkW5bskFMPlEmEkSaqI2wvbuHxiiItLm7gx109SWGwd28vthW0tpuj1xUEO2YJMcwY/dwz2hCUSbmA0T5q/KyNdfjq8kzoRJ/lGH+UJKhyanSApHOLaFBh/EGvwjtwqppuFwY+ODHJTYYjXIiItjnv7fcSrGZifANYJITqFEAngYmAB0Ku1nvPJGQZ6f9M/H+WSXXv2v/wl5qrpxxPLrzj2wuTX2aP3Mzyw+BgtTdrkeGOO6ns8YctjS22tmH80WeHTF4wcoyUsePB3Yy015zn3myLdVj/mey+NnTtzL9+oGePWsS+MKDq6+y7evfuYbavi+Lv6+bXjT2Q+edIZx3zvtL6jC447+lYeo+UrizltluOJ3yb18C371OPezw871h9321cSl0we2z7qwvDYKoSvNjTiuLffR7wagske4GbgHuCXwKM0fUePaHPMNM2RlOx3JRZSFZptPataF//1xcEWjnfOoXpeupOv9QxQnbv3emap6SvJIWVwuX0hOJZNLbLIyIA0FmVpjCkBHDeiqnwCNMvsDsKGIacESOo6pIjPsA1X7k7wjcIWduZXcE1+Pb/KruWO4naE0KS05NLcKt6RW0VV6NZ3PtJrz8e4Lc85aterzmEVORQZJXhOG7hSgKAuIFQR1+X6UVrg64jIF9xUGDLuww2LIDAD97qeZdyypY8RVUM2j80PitvRGAfmOR1cgXEvmVv+5WScu4cfoa5DqkGj5Wh8e2c/7z0CjvXVgtFEAPinnuaKwPPYPfkiyWbOcfvYU0RaUNF2S28aAGnU8MJIUvdtQiSqbrp3JbSRKUPw8LSg0bSoly6UpMbRpuCT37QPaWtWj+4wDuOWJtNe51PDg3SpkI/k17FRzBBPBFgIfBRj0uWZ05bRGU+b3LgUTKg6k6UEU5ZkdW4Ex1Z4TkixSe2dbs5WPdvhxuIQtxY24cZDUiLiiokhxqVplxROC2frNDU9mj8VLxbyncJW9gRpMsk6YfNmYUmFE4vo0jZ7XDMjv7ZZ2NKAsGQrLzsXVSLOiOePes1Cc0nu8IDeUAF76yOMhLPmGOuQijSOOrarWDu+nYKuY2uzImsIEM0CuARKzYvqeVWhjuSApYmEwTHPzXLH8M1xlLpV4PTmisgIqk0p0RVdZvJyeseJfCy/joWB5q5Zc3OcbXpdZqSH1oJpqXHQzEt3cigy6KNp1eAzuX6khtNIto61AiSCPx8bpKIDvN9Bplfp499+H/FqCSbf0lqfo7VeD5SAp4ERIYzoQvPv6Mvtpztbpl2ZVMY8p52vNQcDKyX4XG4AaSu89ohL06/D1rAktBCZFNgeHYkanckadnNG1JCwsmMxBy2DE10UCBb5il9k1yLSCYTQnGN3Mh+P5ZHLiY88RUppOt06i+w2VocepzdC7h3ZxZd6B1hR2EmfsuiOV7kmv564E5JWZil7V3EHHUqwe/JFrsivpvShswHjV9Zu+ThWxDyrxuJAkkj7uHZEj5KknIAFgWa1SnBSZJO1fDojWJpdQC4SZNJ17h5+hBMeepqfZ9dhSSMF6noRN+T6yVkpElrQLY3z89yFe/nEEGk74PWxE+jvXc58USOhIB8Jzuo8iRObMKa7hx9hQ8/rWCST/H/5dSyxy6SxeVvunNYKJC1CPpsboCeMOL97KcRT/Cy7jvZ4A7tJjuhM1pifmiUbKYM4SXnYGUkYSpQWtLfXiIkIu8thgbKRAmSbMSS4dniQfMcMsjuD02Wz2IfOKGSP7TH+jlMMo+7EM2mLINVdx0uFfC43QG+ywhQBPyk+TCwdcJJMsTRyWCBqLNmzm5NSOZbLDNkoYp3sJBnzOTFs8PyhLO1dVRIJn3vdBp/NDRCiaeus8br2hXy+b4AP5C8gOT8kYQfc37mahbLKkvZ5rBRtnBTZTLxrKb26gRcPuV7lyQWqxRRcIiu4XkQ6Vee2wmYcW+GmInqUYKlvaMwxYbGjbyWLozpIQY8R0WNtz2ms6V5Kn3a4q7iD9+bP57O5AV7XsZBTThxnoUjwZ/k1XJlfzYszo9wqFnGq00Uq4ZOzUlxXHORUux03EbJ38XLWqCR/UrqfjDJ939OwINC8pbSJBaLGFfnVrBPt5GNVslpwsh8QTwTcVtjMso4TWB/GmajNEk8EZFXIu3Pn0eGYFdF1xUF6hceq7lPYOb6P87pP5cLYCXRrI6L1/6aXc3tnP6erOGu6l3KyTNHWVmNeKEhoxQWpkznFauOq/BrWyk7OaGjmR41WmsMVkpSCZZHLr7Pnc5ZsozteNa47Hce/Un25UIjj3n4f8WpRGT3Nvydg8sv/CvwEeE+zyXuAH7/cfhp1h4KluL9zNfeO7GrJHzbGTEeolV2qYzZfKtzP+8cG+ZU1g54po8uTTFdjlCrxlh6ypeH52ggdUYhrRexyQg46knHLZvc/VfEbNv9QuJ/dapaPjRjrqGlLcO7IQ4yqGnfJSS5uQuu+HjzL1u5zeUo2mK6bIkgYSYYtxf6KSSU8bQWc130qtxe2kb3tEcDkpGciFyGMV+CIDbPTMaaqxox1NIhxxcQQ14wMUrQUF4xv5wVbs7d0gI+MDrbE4g+cewpPejbV0KE241KtuPzYf5F24TAtjLNF2JCUlc9luXP5TtcAa8Ye5MuFTQyNPMFE5FGWcMBSPDrxHBPi8IKmFFXZWD/AlwubDLQQzU+aokFX5lfzrBXj+uIgM9LigbG9MDXBtLQYriaY1ib3PlxO8nSljUOONOy86RrhlKJSNzeA4liGn8VswtGAAzJkVtuo2ToNLflUfgMvTrQRjU5TfV7xU7fGhGWzJPDpuutpGmWb4ekkVQnVSZeZ8RijImRfNcOUahjj1PEYZSI+NjLIZjvBzvwKdow9zQg+P4xH7KFKpe5y0PIYky4To0men2hnRWQMRScIKI0lqER1pqTi64UtjD6Z5OdWkvUT25gIPUZqJXZR5ikroPPf9vK8FWN8Msn3vRrPuJJ1Txj88UgQZ3wySb3u8LbcOURKUBl3ec6KeMER3Nw3wN3DjzDZiPG0HUMHEYcsTUXbbB7dw9axvSjg0twqHvFHub44yJOTL3DoQDtfKtzPw/UC3ytsozOe5qLSZu4obme6HGORiPO53AD3115kaiRBaTrBI1adX2TXslfWedQzXom7m9DiC8a3c3thG1v0FPv8NAHwSMyY1L61bwVJK8aTdogtLfyGxaywuKO4nZHA3FA/ne/n4XC8VXfYPvYU/1F+iieptvL/37DHKciQrWN7eVaVmSwlqEoYlzaFaJYAzXcKWxkWAe+c3MgflR7gCWZZ3J6nGFU4YGsesepsjXk8q6sUakmmVOMoLZlXG3+wqYxm3CWE2A38FPiI1noK+DzwRiHEMxgFus+/3E7+R2iWPesnttHfu5zTGiFv6D0Dp+0wzdRNRFyRX83O/AoGVAbR1YFIttOWqNPXZU4qGOr1cLnE20qbOOWiKl8ubCKjIKWMl14sFvD23Dn8SdTGh/JrsRxzr/5sboD1IsvZsp0fZ9dzaW6VkS1sq/L2mm1MPRGsGXsQVwtKtXLLHmf72GGBlRty/Xwiv56eWBXHjvi+SHJdcRAhNOsntpHUklhzfnB6x4nUmo/nHZEM3NptnE0sT5EPNAk7YOdEl5nte318vbCl1dZyFJcrw/66anyQzV3nMX7pqfxZfg0uinZFq2hqI5i8ejkX9p3JronnW8W+e7IXoIAv9Q5w5fgQ3yts4zQqXJlfzXvGB1nU1gepNAmt6HTrdAiXT+U3YAvNQrdCXMH4SAqR9LBSggvGt2NJTSbe4E01xRt3RtgI4s1M17kXT3BSaGyWZCaBk1ZcGCZIKkVHzMzMhNRkXJ98YDDBtq1IIGnXAe3SY5aIdEedFGapvaLhs6JgKOoWgjfVHWo6pCNbJR/5XPwRQWdPhXbb58ygjo9iITFcN+Kp0kEWheZmUW/YLYunGBH/s+08ztNp2pqfs8Vp0J6pERMWfSE8N23KKVOWxVccsCzV8o58YbidPmWxMNDYmNxwxvbJRJqv/6qH3kiQsXzmpTv5UH4tDaHJCIeYsFsMN0sqPpC/gCcnX+Cy3Lm0uUaE6sP5tSRjPjcXNuJoOMHrIJWt823HoR2bou1wuopxRkOTUIoTQtGyplrWcQInyxR/Lw6ykSnOqpvrb6XIsGPsaTwkf9l3AbFEQEIr1vacxphtfn9WCeJN9cZLc6s4o3MRf5FYxkJhnLDfn78AC2ko78l2/tr3SKca2BqyKuIS2UeE5vW9p/OQP8JNuQF+nF3PPJHgwsRJxKVDTySY1QG7qZIVLr1ejYxw+Urva0fJVq9g+33Eq01lrNNaL9Nan6m1vq/52oTW+g1a6yVa6z/S+iWSUb8h/o6jmUJPese2E7pXHW135AfHLpg9/tPMUc+PtC26xz6aaXVO/Wg22pcWHVZs2xk7+jD54tiJp5OCo++wA0eQl1poi2ZcHFt41PM3953VenxR39lHvXfBoqOth6498/DzX77kt3TdeWwlrmt+lT7quRSHv+9d+uiCYoyjj+0X7MNKa3eU9x713qrhhzhW/Hr10ft5+Ocdx2x7nz76nD1whDpZ/SW5xpeqyx0ZRxJ9ADZ++dhsw7M6Tzrq+etrhz/n2qltR733pvrRangvnHO4gPYJjv6MpacerUx3c/Iwy/IDbzo6w3db04fyN8Vgdf9Rz8/rPvyZ730JVftj7rHZox+sH32d/S/Vc4yWtGRs5+KE8Nh2W8/Ko9/rl52tx996ifPb7eGBo54fqVT3VDRz1Hs/eIka3msZEeK4t99H/Ldg/qVSDbJasm/ZMmoqwAZOt9qRMcEXewdIdpoTf3thG0sbEbE54RUnzrkjD+E3LBZ6Xa1c6+L2PDv6VtLbMcvNfQM0BEgN0ze8ASdm+PoLRZxFyuGkXXvJhpoFmRnuUxMs9wUOmhv3m07rxCI6lXHX+JfCVh6Zt4KTA3PYfFRrNnpFfjVTHz+PpFJktYVSgngiICMCvts1QCrTIJOu42qQaH7Q2U9WSRZHNpu7zuMvRgfZVX6Rm3ID9OVnOFe0YWfMLCOV8HHTiu6Fs3hI1nQv5V93LuD87qXYcUVNhywScT6bG6AtWeeq/BraMYL/iSOqF21a8i+FrcSE3cpZntd1KkkrRKPpsZK8odegDPzIYlnk8h8dGxAIiCXYPLqHTNrMaM9Ozqc7XWHWd+mIFPuWLQM/RLjC2HG11Um31SkLC6vdIa0lCSvE6kzSEavzwVGzihBtSdy8SyZS5GSdhYH5vrG2kHNHHmJJIEkv8El111keWDhC4yL5emELyU5TxAWoNIWpFqS7mNANslFIp/TQCjKOT71Zg4i5Id2ZKvO1g6PBiwcmzWOZlcXCc2dIi5DNTWGp09sW4mlYEkhK7zuDbnxcL2QBHgllah9X5FezIjlJJlMnngy4uW+AdLqBdIyIlgA+MTzIF2rmptiuQkTSozs0xbr+9JLW+flW4QEW2m18qgnJzKTrPDNlJFYrOiBQAec6PfxjYTOuFzKrQz41PEibcJGWxnEjFiqbnjAkBCIhUM2bb9oO2JlfQUy6tGsLV0ZcINq5uLSJdEedG4pDrOhazLy5AmZzNXmqnSXrNXiwdyWehsUy3Sowz3PaSWNxc2EjuchnpMknuDHXz0hlijQ2oikm1uHUSUiHBBanWe282Z1vrjE0PdrihcY4vcIwFxcLg5v+emELWsOBaIaPjgz+VkngVxJ/0DPm1yqWPfs4pzYUs9Mxto89RTYyBT5V1ZSkxvIODy41KTlg65ZQ6raeVThOREMHOEiuHB8i66SwLcUjpS4+NTxIXBmxfLRqsYgsIK5h8urlJLRiphLjvpFdHLIFE5bVSheoJr107bi5e8fjPhPNCeBdxR18LjfAu3PnsVjHaP/idt45uZHrioPEYwafO4FhMklbEQTGWSJuRVw+MURDaPZZ4VFSop8uDjI+kuLG4hAyJmkIY0lVnbCpTzv0apslThYJnOF0oZVRmXte17i+OEil5tKHy62FTfw8uw5Hw3e6TGeeEBHX5Nezigw1HfK9wja2ju01TDcEL4bT3Deyi1v6BvDskJLUBEKY5Xrg858d55PJ1enA4UfFhwkCi4aWzErJ4t27EW0G3hT6ktCX2F7EotgshJqCCLClQtcDhusJ7ujsx/VCUJpoKmDGklQim7Oy40xccRo6Ejxx4plkInNp1KcdGgLSsQZZbP65e4BqyaHaTI/Mwa4OzI5T1cbduQMHL2lmsV0ERIHBPi/f/xg3FIdoV4Ypd2luVWvmNvJYgoq2mY0cMq7PA2N7ecoKeN/YINjGyaNedZAIhh1JMCu5vbANISAMJUJqDsqQU59+Aith9LknLMFdHRv4VuEBHNvIvgpb0pDGlOH2wjYWZnqZbaZQsk1M/oV9Z1Ktunwib6BqM6rBgdlxvlzYxEeaOsz7gkm+2jNAZ1MpL/AtCjKi16vxqeFBFOBpRUNAoExRtstO8rfFIYCWZ2Wt7HBL3wA7x/e1aNpRIAmBgqox1jCToEBAiObJyRfICIdfDD/CAW2WhePSZYFIsMTXLZ3lCiHLnn3cWIZpwebRPWypH+SrhU3cVBjii70DzEiLmBYsj+f4RmEL2cg42MdExBd7B4iUZL5lVlIvNX79r8YfdI75GJTsM4UQW4UQjwshfiqEyLzcfrb1rOKAI1ui1A0BPxITiCYDKPJBNRWvNNAdCVAKrQJSCR+/YQooAYo7OvtbhYkFosbn+wZQwmhGHPy+wZXOKXUpQFeNbgUYO52UPkzBBQMDCwStGVQYWszIww2uKw5yR3F7S4diLqLIXARbY5pxC8KGoabOWJDwAv65e6BJYpAIAbf0DfCN7gFuyPXT1lbjjM5FqHpTA1iLFhzNQvBQ/RCBwEg9asGH8mtJC7Ost6Tmf7xhjCvyq3Exco+l5o1EImjTkuuLgy2n5V9l17bYTVNBhZVdS6g3L6LakSmbwEdpGH42wwFd45LcSmxLkbGClr40QQhSIIRhVgV1i3LDRfuK3JyehpSsuXicCBgupUEphCvwlCZCsGm6GzUTgtBIS5HSiqhqzoOnjS5Kl7bY5+ijjDJ/lT0swdopYmbww8iRhkpyzodshNTEm+mEOQhh6Fso4BtHSEq+4Nj8Ki6phzbndZ/KImUGLd0IcISh7z+hZ/E0XL7fHEcVCaLQ6FckkDy+8Ezm9O6TCnwheEPvGUihqWGB0nhKtwT9z0jMw9GC9+bP5x+baY0OEUMp0Uor9FlJlmYXmP41J/MpLCYt0y+0aubmtaQW2Hwm108gBNPSorNpAryy+DBtwuXGXD9rx7dzSW4lP86agb8u4IRMDxEmvSMtTYKIvIy3CuLZCLJNEslsUzy/T8T4dL6fCEgj+Y4z1cL6H4oqPHHimWQjTT0yx2plLM/bc+fw3vz5pBW8e2KIjMKszKApBaD5uhdx0IpQWnBHcTs/6OzntQoljn/7fcTvgpL9TeBarfXpwA+BT77cvi6a3YOnYaxmZlxLggb3juwiftVF5oKIBN8+lOfW3gFW9ozSFWnu/fsK4fe/wfL9j/GTMMua7qUMh2UiYGXXEv6sNsny9xjRn1N0FQuD1by+lObbhQf4fGEjz1khl2/0OL9vhEdlgluXTfL3tSe5fGKID+QvMKItZ8Ii/zBopq2nRoTmk/kNPH/mUvp7l/P23Dk0hObg6iV8pdcMrtv9dpY9+ziV5mKo581JtgVtWBq+q1NIDd8sP04+kpz0nhSfHB4krTR3B4eIpQPO9Awv5/UftfiFauP5Fzp4uNDDW6wpLoqdSABcWLd58Zksf1IzGswA/yhdVD3iXTWHcy6ZJRf5fLyJ4d4cjPDxS8us7TmN2wvbuKjvbByheEIm+MwFo/ydXEzOTvOzsECgJNOEXD4xxMaONVz2l5uJMHoJ//ytN7OCNNLS/MSNca/b4NH5Z/MPd6aoH1DsLXYiheZjJY9l6yfZsLFBUgs+K0Oytz2C9Gy6VcD87mnU+DRRWXGv12DFucOcEtURruBnzyxg2bOP0xCCxozN3cM5XrQ1fmTxMGXOqxmccA6XK/KreTDmMPbWJfwiu5YfFLcTk0b7+okTz2Tt+HZEKkm96rC/2M4luZWktMH4frfcRVLYvH9skOE3LKb71AqBgAXKYpcdZ7GTZURGDMuIx36c5jsxgRcP+JfLLC572wR1FfLiylMYGH+WLwcpnFjELjXDPY0Ois9k+GR+Aw+4PpdPDFEMpviRztBpNWj/ysMcciT3xBwuza1iPW30KMGewJRkrs6fz1v9OJtEmivyq7kyv5q3BCneGj+Jz+UGqBPxhVqa7WNPGQRHVOIvigm+U8/SEPCvns0JocDRmhcczT5X8K2YIbkEKNY3GqzqPoUfFh/ih/GA/1PtooHmnamlXDs8yHvshahI8EelBzikqi08+xNORIcyOP5kczJworLJKsGd7ix7dZlOGSOrJK/vPZ3/KR2myzG2uRE3OrN8r6ufv4gM+3Suz96Y6+ePTzjEaSJlCp12yC2FjbQLh91qlkEnwafz/cS04qHXSFnvDxkudyxK9inAXOXgXuAdL7ejjU2gej5j5BYf8jxe33s69X/9JbPNWdsHlx3kGStkyR4DYH/jXydw/uzD7Myv4O3eJMudTraOmYJUXDp8Ued57NvmoB7UcXwhmH9VjhszZc7vXtpaHt4z/Bibhvs4hzLvfiLGVUnjtv1354xyn2qj8/Y97PXMYbou18/USJy+SHJ3/XkWPbaXoZEnANhFhfnbnuGjzUFwaVjn6VNfx5W+wSyP3VNmbdxcdG+rh1w1Psg1SZPP3fG1kK/2DPDuiSHe6syjNuPypG+sfu79iuJia4oTF5RYnp3kNpXkC4X7+eDbp/iuO8uiMyb5WswsJW/pG+DDyueGLT38Og7Zf36ckSZJIhtPscbpof1WU6S7qO9sfjH8CB/WBzhDV/jq5hy3Oeb7zZFHZLNTfkKO8+9fXs87Kw+zo28lH3nfr3kUU2S6XM5wccMjlWnwV5eWiZ9sszBjijh/E3g8vzXD/W80UKu/CV1KH17Brh+lmBE2QWAh+0wh8M0Nj+0P5thtm2rR2047wM78CvZ4Fm4q5JLFB1rL71U6xQtN4aQSIauiOMsaCndZD3/nTPCO3CpqygwaQmp2LTiLe/5XlUxXnQXdM/xtM3V07fAgf/m6g+wJzErqK7vno31YEVVZHVZZ75Z4smGKdD3K4ow3lbi0Zj736n9X3Pd/svz4VM3HD7XxH/HlrcJbXsb549QY+dNmuKWwkXNCl+90DXCrns9bVBlfWZQ+bNh7b/HrjEZV/i08SFnCaU5HC6/7FTnMhd4knU2lwJ84ZX5YfYZfRSPsj2b5ZGKmVfw70UrztVyVq5t97H26xi4nJKEVNxSHyEZwVd2cz0PhLEOex62088XeAf60ZvPurCn8bglG+ELfAP8pjEXVz7PraBceZwtzbf5D4X5GpUkfjaoaZ3WexCea6YV3+Wkirbm9YAqmI8EMf9fsQ8tCm7/x2/knOcI/SIsp1eCa/HrKElbXQ24p9Lbo1q8LzWz/tsJmlsk0bwgrbI/M73ppcfi/GtEr2H4f8bugZD+J0csAuLT52svGPjvi9BceY1nHCXRG8EeyC5Rhrmkl0CE0mqmKGSnQQYDWEa4bMVvx+EZhC5fkVlKTgrFgljoWEYI2LShZZuagGz5CarrsJA6Cecrm+TOXklCKSEkkgq6mc0L3T59pnZR2BTORw7SIWuw7tzlb+Eb3AD0iRqWJ7d3cdR51YSyD6lWHbFuVGctoMghhKLIWmh92rDci+UDG9Ukqk0o5KTB5wpOdLOGMUSXzAwshNV48pAObd+RW8c0ftaPQRDWBh+Ty3Hl8cniQMJJUCHleVbi/czWBMBjaUq1Ml7a4Jr+ezaN7Wid+DpURACnpkpUe1+TX40rFIuXwva5+qqoBbozbkyvRRo2Uu4o7qNUdgtCiIQTxrI/2Izpv34PrmePU1V5hb5hC+4pi82KmHtDQkndObqRScaHhI2OCQEBVNiVdpSBqCFYUdvLp4iBh3SJsmuLG7JCCDNnfdIGxMS7g3aJB8PQYdRVyV3EH08JIRk5MJ6jUXRRQn7Vp1GzKVY8A47xcGbFbqS8PwdQBc2OYiFxKlTjPzhbJaovOCHSosdDUyi6rdRoLjY4ECWGRdAIcN6Iy7XF65Bl7rdAI5WcizVXjg7xfPUcQWQRaomfrZJuHxBUWSekSYVY+P4355HBxhUUUSca0T1mHVHTAvqkC86w0WRmjWnWZava7ig6Rlsa2FZ1KsCvMkECiEHy3a4CSBa+ffIBZ32WxnSXCFHgF5rgLqflccYisFScADobTqEgimimToJmG+Gb3AF8o3E9c2JwoU5Qjk6+xtdEpz0qPf+oZ4NrhQRoqwMbopoBhvM63MsSEZJFlCqGeNgiJnqYeho9i2NIojLLiJGErBdIQslUUfbWhmkXR49l+H/G7oGT/OfBhIcTDQBr4jTibI7Uy7qruJ6st9i5ezu7JF3nB1vwsLCJso4wmHYWw4alwCo0p2ol4DGE5+L5FKtHgU/kN/LD4EElliBoRgrTr0xAwI81gOHKngYEq0MAAACAASURBVC/NqAYThNSFZtFjexltGpZ6wiauzGAIZkb17PLT+OjIIF1enS8XNrGisJNQQCVqcGHfmdQkfL2whV8OP8r0teuYiVxuLmxk/YSZNYS+RUpp4qkALx6ggI50lXHL4hPDgy1absmCtwYJqlKwfP9j3FncgZDwz90DuE5ErMNguZ/Qs9xV3MHzMjD06hmbO4s7SAiLL/UOkIz5NLRiiUyxfmIbwzatGU5RhHypcD9nd53M3cOPcGV+NV9jHmvGHuSgaPCT4sOMqhpfKtyPBkpSceX4ELsnXwTL5m2lTaRSDaa0z9LsAjwnpBbY+ALmbdmH8MzM7tSnnyAMLRp1h5OoYWU9ZglNAVUK2l2jLRxzQ4jFsDo8PKXp0T6OBiEFwtLszK/gO10D2LGolWMf9uOEaOYpM5MGmLCgriy6fvg0D40/w/vzF/BNdwoLQW9nmanQNeiESDJVjbFm7EHGRUSbloQNixMyPXyze4Dri4N0nR0w5CRw0CQ9n1m/Rk8ERRsINWVhkemqMSkVDSF5//4UszoglWoQNbHoz1hN6VPbWKRdPjHEd7sGaHeSXDC+nbKwkF1pZizYaSW4d2QXG0efbCFMvlPYyj5dZePok/iBRVkH/LD4kPk9yXbundpNDCPINaXMsZzVAZZrpGHLQhNXmkWhxNOKQMAi38h7xq0QH8W4CPHskL+vPMa7J4aolV0+nF/LcDCDBTwy/iyxdIAnFM+HU1hSsTO/gveNDXJR39nUdMiwrjPRmGn+5oAxW5LCapn6pqwYAoFtKzJKEyEpRmUiNE+FU1hAPoi4uLSJYlMwbEv1RYoixAGe9iy+XXgAS2juG9mFrfUr0qn5bfEHK/sJv5mSrbXeq7W+UGt9DvAD4DcqFB2plXFZ2wmkFNiu4qzOk3hzUONqcq1vpyOBdOFMuwMBpCJlBH+VIpHwSaR9hoJhANxmBTHnVol5Jo3QGZnin+2ZAWou/TDndj0viNgtEvxi+BF8AT/LruOS3Er+LL8GrQTXNXWYweToZoWmHjUYDyu0HbHWafv8JuJNTYXdJ5+O64V8OUoab7+amREoDovvfK1ngM4Izh15iAWBwlO6pXfb37sc6cKfN7WGtz6SRytoa1bsM1hcljuX0Lf4cH4tXTj0hRppaf73WRPEkAx2rKEnOoxJnddc3l/kLiDheHyvsI0Nk1vZ2LGG3iaW/JfDjwLGtDOuBbfMwZMs87/VqsuPig9zVswQeqTQxLQ2xa6ZKhPvWmrOgxfS0VchGfNRjZDlUdMJXQqW/LEZTLx4iPBcCI0WdVlbxoQ3YYMWpNINpiyQNkRNqEACkztWzX7RQLWQBaMXLeaP+86mHZsFMkkMSaNmk3Ua/PFfeUhL0dtZbml431gcakHCkkpzU24AYQtSylTtXTuiN9lONlTMC40WSkJHCGmKbY7WbJzYzURUo1z2iKcCXC+kR5sZ3q6dvXjazPxSSlGLzBwloSOIIiSwSlVa7uMxBJ/Ir2dDz+vICzNzd2zV8nZMC5d2N8Xr25eSFQ7xeECnNO3mSVOfUZGkUxlLsKows9FsZI5vl1OnLVNjSjVox2L16A5Wphc1z0XAfO0wE85RnsBJRAg0XVaC0SDG3ORxmUxzZ3EHaWFTqpX5cH4tC5WDrU0Bb2XXEq7L9fNCdZSksHHciAlL4AjFlbqHt9Y9qtrchnbGTD89OzD9enGsBxejRjja1MSWQrOuZxnvnNxIh3ptgGSvJVxOCPFmIcRTQoh9QohjyhwLId4hhNBCiJdVs3rNKdlHvCaB64DbXul+/9V1Xr5RM2q147ex6bxk3jHfO10cDcz/pxVTx2h5NEvv5eLy+vHfc//DO7aVztoLikc9/+SGY6vLffyxruP+zFXdpxx3298W8SPIEy8Xu39y/KphwW851HNInbno+cWxbcZu/cqxCRIvjfPU8ds8Pbf+2Jm6M1cefY7unpc6ZtsL+8487s+8f+aZ427bZR3bEuqVqN2dkDx+27M/deYf873tztHnwf4txbVbCq8dBful8VqhMoQQFvBV4CJgGXC5EGLZb2iXBv4SOC7WzO+Ckn25EOJpYC9QAL79cjuJp3z6QjOALXI7WOPbJJTBegI4aY2wBbcWNmFrTcGZ87iXpNvqCKnZPvYUf5Vf31p6JJM+QWDxgiPIRIqUiBCpBImsGUDOC9wWWkEeoRj2nB0RIfjazvm8wY/hxCNODA8LZmcydRoCVqcWsXN8H+8ZH+ST+Q3c1DRlHWhqG9u2QQ1kPHNhpLrr1KsOHc0Zdm8Y4mgMPhaIacW/Fx+kIeDQ+Us42crg5D02dqwxTs9ljbQ1p+k4789fwC/v6aNXeLQtqJNpAvxtrQlDySk6xk2FIeJ2SEJp7ujs5819Z9EVwa29A8YqKzDFlx1jT5NN1khr2TIGAEg5Pomm9vTre0+H0Gdz13kkEj7X5foNRDDlk4k3iCtN28kBVk8bMulw6ILFeLGQypTLdDUGSlORxj1bJGNk26r8PLuOeMZHl6ZR9YgxW9IuA9oiRce3n8BOmzPZHoGVOqxe19dW4RuFLZzkK+y4YlaH3NHZT1+qwsS7lnL38CPcUtjI1X6EBdhuRMwNufqkA3jJkFrVMbWM0Obq/PmkFwasS53E5RNDfLo4SDQV4jkhWbtB3bc5O30iDmYlU3rfGSRliF+1OM0HW2uUD6fbHbS313CTEV4qpCY0+5Ytw8oYd2gHTVwrbp7s4KlTlpOUISKV4KMjg2TbqizyOqkqn4wyq5t1VjdfKtzPm/vOIpE0x/tT+Q0MqwrdTprL2k4njUWyrcEiEef2zn7S2EhH48bNim1L13mUpXHHGbUlD3hRy8Pu434b8yOJ54SkmyuwVI9PT5NiPkcbCKoGdHj38CNIoak2HEOW0pJ1PctIY7dWKHENp6oaOW1zSkPxueIQZ6QX0oGNZSvODup0JGpGwiCmOc3p5B8K93NaQ+FKxS9to6vdLWOc3zB09zua8LhUzGfT6G7+s+P81y7H/NqhMs4F9mmtn9Na+8AdHK6xHRmfxaR+j0sf93dByf7fWutTmtu1TenP3xpB3aYuBKFvBHmqUvB1awzdZK1NvRAjqprHDWFgTgSmA9YqDpVps0wWGDcSgEbdpuo71NFUpWQSB3yfyoSZYR+wdcsOfdS2qPqmg54SWtSkpChCDjlQm3aYlYf9ympVQ3TY2xjjjb1ncG1+Aw7COLB8zMxAvtg7wMSk8TprBDbjtqA+7VCrO9Qk1H2bacuiaNNy2R61bRa355m0wK9Y1FGE4w2E0Pi+hT8rCWoW+4WPg2DYEcwSUi66DDfT+KEQhJFkRijekVuFH1nMSsG7J4YYDmaYsGC/ZcR9Ls+dx4hu8PbcOUxU4hREwIO6xNLsAj6Z30AlcKgKzV0dG4xyX+AbgkIkeVGYm0296jBb82gIgT+p0fWAaLpBfdrBbxjfvEy8ga4rqkIzPJ1ENwJK0wlzHis2OozQvqIuYEo5jNuS8UtOISzDKU89SUMaW7E5+vVc8fUdkxtpzNgsFEaBY7ySoPPfDtPEq5FNBYWKJDM1D79sbJ3mtFJesBWP+2NUC1YLefHZ3AAju5OM1+LUIhspNaNhmadci6qEaLpB2PTaK0tBybIIa5J/LGwmDCW1KYfatMMYgSHZTClqAiYsi7IwxeXp6RiRFuiZCrd39psiodZEWjMmNR/Jr6PUJAJlhUel7DIpQg7SwBUWhxolykRMEuJXbaYxEqWzhIQ1SaNiMyY1tciiJoxIUk9odEb8yGK27PGW0ibuk7M0Apsp1eDX2fOpTjiMW0bpri5gYaaXKBAIzHearXm49uG83VRYpUxEMTRojQmpmVEO4yJqXYMbR58kAmamjBNKqRpjBJ/ndJVAK67Kr6EiJaXI5TSSDOsGz4fTTFuCsoRs0118TnZhRLgtW6xXG5E4/u3Ielhz+8ARu5oHHMkzP9h8rRVCiBXAAq313cf7/f5bMP/8hjFrXLrvCSwhec5WvF30QKj5TK6fRLsZeK7KryEUAlcDUoCQWLbCso305TO6QqKZFFpR2Ek1sjk1gFwU4GrFyPcP4CZCPpnfwI3FIarSKLillca1It7QewYFS5NREbcVNpNRhpbqAAk34MP5tThuRELB45P7uXdkF58vbOSmwhB/Wxyi/daH2LdsGQct41+ntKFyh5gZXzLpMy0NCaQuBB0R9ERGtEgB+6YKXF8cZNFje3EQCCk4QAzHibA8hdaQwuKpaAZPw6ONESxHcSiq8LH8Ot49MYTnhgQYw9ZQSxJKc2Oun0cnnqNdGbjTvxcfNFhfYfGxhsfA5FYEgqry2Vs6wC2FjcZVBUFZSu4ZfgwcF4mBn42qGut6luHFQiyp6FAh87bsQzcCZMIgHwqTabQSTNU8kAZR0xGvQxgRacElk/cTBRLh2ghXMi9QBML4Ocp2l6ZkMp2hpj5pUAM39w0wVfP4UH5tUw5Wk9KCF1zRIrnMGc3Wkfz/5L15lFzVee792/sMNfZQPVaVBBJCQkISQohRQi1128TYMWBzPX8EG8fYTuKYa8dh2cuxcZz4ejlxsLkY7MQDxiZ8EE842OBAjFtISEJMEqMkJCQkoeq5q4eazrT398eurlYTN8YJubnx966lpTpdp6rOsM8e3ud5n8dFmOpC4Ilj3WgFoxMp/sx3SGjBUqcNaWlG/MnG7CyRCjjsuIRaYEmNRPAveoRIzGqQxJsCDtgRMa25cL+hcY1OpPBqNkLCMhUjDC10CDZGQMuTgnumzcAxgQNScMXYFnZ2nse+2hCBjogwWtg3F7YRQ/Dg9AFsS+FhlATvH3yShOWSxjBOKmWXvy88xFe7+xhWNYKaxHYVntCMShdbm4kMwOm+ZPP4TpIxo4Z4mkhRDWw20cpFxR1Yjhk8y8onrmG0NkkUSMrapkKEJRXnDj6GxqSXTo91UdMRU2GFA7qMBCalxTFdZbus8Kk6SFfQNVw3oiwFltAcCSdJCpsh1VBVx0LToQQHg3HarQSDlqYmjKvQn+Q34joRb8ieSVwr2phfH+W3id8mx3wiHlb/981X+zv1lO5XgE/8Nsf3f0XHfEVpClfDE/l1OEh6qxHfj47ijyoGhCltjqqCWws7WZcaZ7dlVgM6qDI6kWJqOo5EMBSWKEnoSDZzR3sv51w2wV4Xnoo5TEuLiWISr+wwTsB78+upCoh3awZswb1WirVWK2ktCOrLl6l6iWtcQclz+XrhIeNLWF9WX5m/oHEOb82dTfEPz+C+0W5qaBJWSLkc43/bxnXYr9qMTqRwNUz7Lh8c6efvvL18eLifWmRx9YjRAbgm38OB080yMZzSXDG2hVIlxrPPdVOejCGAqvKZktBiJbBjRl1ujICbu/o448iTXLd+iJ8OPE5FW1SlaDwAB21F8epZx43vFnYwic2DbeuZJiQpZ/P1FW3xMFPImeRQrcLzVpzpUoxAK94hujk63EIxiHHAddi9YJ3pdCcCfM+mNe5RqTpMaYeOHz/Pce0xXYuhqwErN5nOrFSOoWsB2lccc41D+VIqqAmf8ohZwQjM4Bj6Fp8c7Meq89pTygCCPwuO8+mBfsZxKPQsbQjfNImQYXy8mo2vJBd9MKQy5SKAX7pxRkVEk7CpTTv0pJfy7rEtfHagn6HhJorSGB0MVpL4OqRPdlCwNCOXLuOT1iilYpwAzZQlSNkJ3phdiyMVn6gYLep9ska15vD0U90EmBXZlaNbWJToZMp3uXx8K3/5oyQ3dfdRjWxCHXGe2824CPlg/kI2dK7gqK4RqIiK53C0Liz/puxZjHlTbPcHiNAEoWGUCOBIUEQrwaeLaVxtVkl/NbCFSWmxPyYpOIaOuebYHvJ2EyUUV4VH+ElU4NudfRSHU4yKEAvJqNT8efsF+J5NSVqMaY8bLMl9mY0UHJgg5FeT+yhEJQrlMVaSYkiEVKTgxwOPcjAsUqiv4jqES7XmcMjRDOsYl8gsU8rnuF/k+4WdjFtQE5JdssKZbieR1uRDwYRUvL57Dc1YDJVT3D/4JJePb21o0/xH4zVkZRxnLiV4Yf1vM9EErAa2CCFeBC4A7v5NAOD/FR3zLe5ctbHnYvODf2cceXLOdtyeXzXs0bvnGnQvu2L+0fbiYC7wNvR7s9ZSB5y52OwrQZMvd/G9uja/+t17kyvmbD/ILOD4XDQ5570Fmek52x/unQUDZ5gbM/G+7al5f/PP7p0LQH3NKc6773Ixd98bokON1zOOMDPRtWju8Z0Yo5fPBRj3b5vfOP0hey4weMidP8cXenOvbWL57GdHXqZYOHrP/CKH+/y5KnArvfnb1GfDuU5p/7J49jf/9mUN4/Rlc7/3K2L2vlz3+tE57339FdTlFlhz7+dCp2WePeHT1lwQ9kTw6gMvU5f7pjxl3u+5cWKuWuAf1OYH2T9fL/yZiXda84PsL9e6+PgJ7WhYzU2/voV2/rPiNSzJfhRYJoQ4RQjhAu/GaNIDoLWe1Fp3aK0Xa60XAw8Dl2mt55dj5FV2zEKIW4QQw0KIZ074W5sQ4l+FEAfq/2fqf2+pa2Q8WdfQeP+r+Y1mpSl5LmVtjBvfZ52MdOFbhe1YMYV0dCO/dLKO0fype0EpbEuRjAUMR2VKkfG9Hq1MsaZlnIQM+WJhC50hBEIgW5tZ/vwzfKewgxZsPjnYT+fPDiAw5ozXF7YyWqfo/M2zeSKMFVVMC8p1qlnCDZAIFjS1c1u9wulP8htZLtINEZ+bC9uIOSGJeIBCEFeQaDYziEgYYO22jl68+uxvBjD8xeBuA3C6igeGnsJKwi8yG4m0IJH2iScDri9sZcfIPm7/VY5pNYu4d+LSFmnuy2zknsHdjZs7bENaC9Z3rjBFNdo1YB7GY/BXQ0/jWhFx6imLegRC8OXCg7RE9bxi4HO1swQvtOmUppIvZYd1XQOwEhpsC9lsk+k2TiGuE7EoZTrsRSJOoAVttz2HxoCQ5iAFqmbob46GzsjQ0uLNIQ93nUtCgZA0OMKyfs3aIvA9m5OcFr7R1UdSK7wXKo3j78Yng0MYWkgBjxe6KJVidLSVObumWBLZRmEuHpE4YaWwaOk4GsG0tMg4Hp12E58b2EI2Eoi4xBcSFQlSGIGfKJD8y+AeyqGN7UY4TtQwJHVSpi21RAaA/YmV4qLiDn6R2YhsSfCnQ/0krJDDk4bqWSLiW4Xt7BjZx5CqsCSVxQttbi3sbBxfe6wZC1NUJITmkvRpZEPNCrfT3FNbcYAqf5TfyLX1dEJagYfGQ7C943zuGniMGhE+FgrN1SP9WFIhEDw2eoAvDGxhUbKrkUu/e+BxakLiIegKIacdzmxazOl2hpQT52P5TUbtrj69zETw/cJO1nUsZVT7VAObfCQamjQ1HbIo1s7KtpP5fK6XpFaN1NrPBp+gSWlGCLhmqJ8CPun6YPOj19TB5LWhy9Wrnv8UuA/YC/xAa/2sEOKvhBCX/XuP79XOmG8F3viyv30KeEBrvQx4oL4N8BHgOa31mUAvcH19JJk3zhl4nGddIyRfUwHtkSYTgd1sDq88GkO64CC4s72XBZFg6suXQuixrvAE09UYF1ldPDt+hDODGm/Nnc2qQ0/RnDAdVy4KaItCtOfz4lnLuS7Xi1NPVxw77zSW+iEJJ+TWjj5W+pJmEdR5qoZb3aUEC+vl4rF4SFxDLmZm+Td39VGh7uAdzM60bEvhuBELMtM010HMXOcU+cC81xJFnBZIvldXfpuJL+T6UDOdUNKg+tmuaWxXYbuKj+U38YH8BhIKet08Vsw0nbSWvGdsC7n0LK0pY3vkA0gq2Dmyj65IkNGCs602Ppi/kGuyF/Ke3PkkYgEnaZc31zWgr81vJmebFYQNpiN3XNYGNTKpKotEnA/mLyTTUuHi4kOkFWQfOIhsSiCkIKhaOG5EIhkwWYkj0zYrfUkuU2LiT88mZkfkA0WmvYKwLaykZImvaFEh6UgxdsXpWAnj+bfMDxGWpiVrjifpBpyqHF5wNC1dVdaS5o+H+7FQ2K2Sy3Jn85lcL7ZU2AiaM1UyiRptOiC3aIpqxWFBvMzHh/r53MAWnETECqetIWIUVC3ysQoniSqWNIUNX8j1GYXAuEVO1kikfTRmdZTqDvhovoeOVNUUEaVDbixso6WlinBNKiatImytebEuiRkXEVgWd7VtwrGjhh70OVGcP6tLBVxgtbPR6WbxKWamf37ncpbJNM+NH8VBcqpySac87q8cIlZn9MSbQxJpn3U6yQW+Q7uSZMOQpX7I0gDaLZ+WdI235c7FQrAoM8kqp50H29aTztS4ubCNN2TP5OauPhY4LSTSPksiw97JyRpZt0pXGDIiQnwdotCsaVpEhYibuvuwteYD+Q2klebL2T6arThLRZLmhEdLpOmIQq7IX8Am2c79g0/yB7FTWV8zRVefym/mhwOPcml2HUVLcEYUY3vH+eRwScZMx/z219DB5LXkMWut762THU7VWv+v+t+u01rf/Wv27f1Ns2V4lR2z1nor8PK14FuA79Vffw9468zuQJMQQgDp+ufmXxsCd2d6+FI9d7RjZB9PuZr3jfY3zE1P2/8s08dNjvfdY1s4aEf0f3ESVF0msaXCXsyDuyUW46cDj/NY7mx+HrUCcMx2GLZtnv77KqODaf5qYAtfqRddxDoVlxS3ce7gY4zZ8JQb8YJlJOIPSI/p8TiHrYhnSmb5PTRhBIceGzVc0o8M9zdmNNHYLP91rJygWnFYdegpipZRWts33MY+V1GoprisuI2HHZ/3jc5d2n1moJ9Tn9kLQO245uLiQxTHk3hlm+nxOGUivlPYwYRlgDxvyszOjgqPL2f7WHNsD8NvNmmY/TrFU27USK8ctSKOyYhDusK3Ctv5SmErdwzs4qVymgOi1phpN2vJAZWip2slBds2dveBT9/4TtYc28NeXeJbhe3sHTe6DtN1EFVNV4mmAsbHklRLLtPThi3jF3z+QQwwUEzTetPjLD5/kglLMjzUhJosU3gsyb/GI95UfIjDrqT99r1MHotzX2YjJWlxdH+G4ReNRsKhWhPXDvZzXPiMFVL8vzXDXb6ouIPpQ5K7Bx5npxqnFDk8Go4yPNTE/VELFxV3MHCkGTcWkkz6jdnkkYNtfLewgw/W00FuOuRr0mHj6C46ukuNezIsFaoWsdtKUpqK87wu82f5TbzpSc3XCtt4vtLM5FiCqdE4v9e9hqPDLVQGbT421M8lxW3sjGu2Tps2M61tkAYArfgOe8ZMimiXVW20yy8WtnB9YSvFoSSfyfWya2Q/NxaMwtsPBh7hU4P9TE3HaXea2F3XcikWzHV/RJTwJGyhyDHH5veL2zjgGFupwmSaHw88yjcL23liqo0zozhDuFSmYnwgv4H7B5/kUdu0hYlikmecGD8p7ePC0V0M+Em2JyTTRLzkjfPNwnYeGHqKF1WJPx3qp2QJvlPYwZZYyLWD/WwZeoYj1BgtJ9jphjwct5jWAZ+tFwR9eqCfNxS386biQ43nfyyqULTgkBVyk2M0sl+smpTal18jLWb47VgZ/xXxH8kxd2utZxKdg8BM8u0mjMBRAXga+J9a638z8JxIQflU8FxDM/iO9l4urgbc0d7L9F3X8o2uPobfvJSmk3zuatvEoTUrWFWnzwT/+D0On7mCWCLkzoFdfCC/gc8PbGFz1yo+qQI++l6fz+V6yYchl6w+RnPCozVjOvAZO3YrbUw2b+zu4wlZ5QHvJa4e6ScCzopirDm2hzdUFavTRT6a7+GMC03e8JSWLGCU7C7NruOdufOoHo64vb2XP8tvYgSXp2stfClreMMdb8pwWXEb3ZFkYarEbR29Dc3nyc/0zrk2R85ezqfym4nnBHdnetgTNVEcT5LO1LjKD/mj/EZaI5NCGRtO8YvMRvK4XJoe4YbuPpzuBG/Nnc1lbx7mK4WtjSXgVwpb+ct3eSwRSX7ctpkP5i9kZ+d5dDg1vto3wV1tm+jpWkmI5srRLbzJ6ubqkX6eXbKGL/y5EY/as/Asbv/eW/mbbB+nJKc5PTPOAekxejyNbE0TTmjKgYPtRjQ311jVN0b2gYO8zs5yY9zj3kwPdmeC5kjR3lYGKclfUOXyqslFv8GaZPzKlTw32sbFxYfoUD6LzygyXEnyhVwfC+0Kf53r4zuFHbRly6yLL+CN2bV8IdeHmw7p7V7NzU2KhAzZbHXRnZtiUaCZ/PxFnLx6guJkkhurLbQryedyvVw4uqvhl1joWYrbJlgfxnmk+xyeONbNTd19fDTfQ5eS7O9vpSqgtaPCXQOPcd3bK6x1TbN/5/iDXK9itHZX6ZAJBiyXasnhls4+rs/2cVJk8eGmNexbupoWEfLDf0xyd6aHb8Vm73snLud2nsY76hZQAI96ZnLx5uxZ9Let58vZPjZ3reKq/Hp+bKW42U5zlqf4k/xGU8rvZTiLNEdszTujDCcHAd/u7COO4HM5w/d+b349v8hs5MrRLRywAn4Sq3G318Z3Cjt4U/Ys3ujFuD7bR1tHmWuG+lmXOomfZ3pYEC+TjSSv810uSC7iulwvX872cbkyq8dBS3Npdh0Sk6q6Jt/Dx3XAkpPGWe/b3Bu8xN0Dj/PpfG9DROz29l5+nulh+E1LuS7XS5edojOEGwvbOFnEuTa/mam6U/fyV8j9/7bxWs6Y/zPiNQH/6lzlGQDzYoxuRh5YC9z06zSZT6Sg/Kh71rL957EaFxWNHGDt1p8yecIRXj6+lW2FHAB9f57A/dD/JKiDa1fl19NyApXmgaGn+Nr3TQYlQPDkniyL/tCACdfke9gRnx0KH7q/i9fVVbne7Sziifw6PrnejDkHV67kuD2L6gzsSTUkEK/J9/AXKtd4r2lzFxsWmnzhAlljlTvFeb5Jp0w9OMqB02cLgq4c3dKYARy+dZL7MhsbOfRFj+9vzCAAejuGyJ9iwMAPqUGOqDLveK8ZYBacNslnLVNh9ux4fCGD7QAAIABJREFUO5usSTK3GAut5+5Jc8sJOsPXZ/v40j+ZEt774iFNWHwCo3XQfvtefhGf5ak+0n0O6XqrXHXoKT7z7U0sazWgzseu+gV7xGw+9y1Vi7OOm7Lh+KkJTsrOApcv7UpR/JCpavtLoVl/+QQHf27uSywdIltmwbNHtnQ3vmfDucY6a79jeq6Vy4YbpdczMZPyeWeU4TK7yILtZva84uAzhHq24Sx1p9l2g7kPLXUX65l48azlHAnN8ea3HeTp7Z2sCE3KYUliuqEWCLB8c5Gz6/fz1o4+nvhHl/91quFAP7tkDZ85IY20rnmcjhXmHnWERjD/yk7TNia13bh/n5Ae6ztXNOyiFtstczqDTZkRvlAH1/rGd3LtYD+rbdMRXulO8FNmrcKOnnMaVzSbicNpvmDYomGNlInmgnRHHYdnlxiGzv9Tc7kiP2tVVrQEt/hmFr+943wcJN31qtS2CPafAHJeO9jPaB2DfZMq0SxdNnnmObyxsI1/ELPeUt92mxsVjhOEfCTfwxVj5phu230Sj+hZ8Pvmrr4GA+Oc5jEuza7jtYzfZa2MISFEDqD+/4yJ2fuBn2gTB4HDwIp5vgMwouzl+pEcDia4pbOPMVugQ21EjFxJVJk5YG1ctIVEq4DSdIwokLhIXqrn8B4cfrZ+gCEZJYz6Wb3aStoKH91ws9PKuHSUKi7TOiAUMF6N84WdWYSGpc89R0mC59ucFRiAJxMqlieyVFFMSgNY/GDgERCSasnYKM0oanU1lylaRtlMRcaaveabhjtZB7KC0CJAUCHiR22bjU0TgC3whaRaclGhIAokb4udwmRU5Y7bjJiPjMNjowcYxCehFWE0A7BEDVWuQUfSnWplRCpiWjBOwIj2GME4dIAxka0SUdMhh4WH0oJJaWQfL8+dA1HIgYnjhJEkjkWVEKUEoxMpNMLoT2iFDiKiUFKpmM7XthXaC6kIhZQarTVaQ0xrxgYM20DXFDUkU9IyBgI1M0A8u2QNx21TXRd6ssGNVWg+k+slCiQrSFC0aDhzz+ighFoQCI0KJUFocfqCUaKqcYMBww6IYVJM3XaadD0tJtA4UnHekEkDntKSxUVQFSDixo4p9CVb3BpFHFQgeHP2rMYgoRV0CpdVh54imICKhJRS3J3p4aPDCSIlSYsIgpBxy+bpWgs7R/YxFkzTpa36LE1zY3efcduOjBHCTJoJYHcwYuiUoeSFegqvVNdCtBxFDY0nYXFgQFUJNEemrYWRJIbkw8P9aCU4qKZx0A0tkggjeiQRhL7FoIpT0SF+aDFWM6BvKDRT2me0rgtTFBHX5Xo5FqS4vfAw01I0WDs1IixHM2gLKr7DEtmEQhOg0Wh+0LaZOBEdIZwsU7SLGBawr862+nLhQaZLMX42+AQVaTXs4/6j8TsrlI+hhLyv/vp9wD/XXx8FXg8ghOgGlgOH/s2nT4hVh57iqG0ejOfLBfY7pmIqKJqrUngsiV+yuCq/nkFbsM8KIIrAr7Ku8AR7h9upYQCQWzv6+FK2j7szPbylGvGxoX4GHclBmUAVhqmVHYZ0jeOYmc/kXsmYLblg+FFGwzKfGejnBSfGDYWt7LNDnsivY1JC2XP5w5F+RidSPBGHo/64ybO6quGT1/KlbfiezecHtjBcThJGxpUlocCrOgyNpTnoKAZC08DT2iwvx704lxS3MRhV+FGsxvFBQ4cKxyMKjqTm2xSOtjBRTHJM+LxQGeSQrXghmmbsYIK35c5FIPj94jZKgct7cufzL4N7mBAOJQl7rZCh8gQRsJtpjiuzFL+t8DBr25dwwfCjHBU+e2qDfEQvYFoHDIQJPjvQz4hl80jpMEyb2UzFN3ZOPx14HC+wGdMuDyUEZxx5kmh4Ev8ln+npGNOeyz0TXewuZfCPelgIJitxVClgzI9zxLXwQ8t8Zgz2xkyV4nHbnHd5wOZwsYVsJKiMmbRAgGYgTFAUpuR3qphgVER8YrCfXTJFocfk1jd3rWLIcjiqa4yMpBmM4nhVm+nhGANlMxhck+/hDu8wAC94ow1gafFJRYaUmeWNVBIcnhxkhIBxYSRNX9IJiuNJKjrikGuqMaeUx/h0kkrZZXIkwaD22Nl5Ht60qcI75kh2xy1e8EZNh60luuTxkgMtUcSy1gUMVMY5KgICFHcNPMZjVo27Bx7H9+zGDH/GZy9txRjRPmtf2s1ef4THY8bLcXIkwfhoiimhyAYRP4vV2B+zjVh+nXa4rvAE3ypsp7d7NS9ONlOKPF6yHcaGTR73UG2Ea4b6mQwrFCcSlKTknsHdFCOXi4sPMWnBw9EY9wzu5ogqs7Q1z/ZgiEERNFgXzzuKK/MXsKx1AaHW7DvUSUlonpRJ7i+/wBFd4/t1XGbSkhy1Y+xyA75Z2M7+sMheRzGOAfzemjsbXZdDGLQFeZF4pa7kVcfvRCpDCHEHsBNYLoR4SQjxAeBLwO8JIQ4AF9W3wdSEbxBCPI1ha3xSaz366753JvYsPAuvvmjwo5C/KTxIewQLdhiwJLumhB1TuEiyoSY/Y1PkJnhh9eksbx+npiMuza7jqtF+PjXYz2XFbfwq4XJzVx+L/IiTQ4/Bn5WJJUKWiCSJ+pz51Gf2ojBLpy47xRdyfQ3Zwq8VtjVYGEk34JP5zTQnPDJK4quQN2bXsiSUPDD01Jzz+etcH82OT9wN+U7QQlVCU3uNrkyJNiVpqlvyhMIsLy8uPsRdbZt4YOgp7hzYRb7bLK2la/jCcTfEC206ukss1i5D5Qm6lPndzEIzY8pgc2d7L68b38FNr5viDdkzyckaSWXoe+s7V5DWgmUixWRdQ3dD5wq+ITt4pPscvlvYwUI3w3JRZqlI0UrAdbleMlHI8ekxaDK5zqQbNBqNY0e0EXBBnX4qW1PYbZJ4zBie9jkTrE0VcfIOMS3MZ+MW5/3+GNcM9dOU9pDNSdx2WO5HdIchnx3ox+mwSeVCLiluY5EfIW1FqtXn+sJWuqRHu7b4Udtm2nMlFAYUWhN45LeZVMaDw8+Si3wWijidnSXahc+CtzeT7vDIOGZAvrGwjbfHFqMiSW/8ZG7p7OPT+V5OeXIfz9XBtCbbdA4SGqBcmwpoaamxlhQLA80nh5upqoC2pgpuLMRxIk4SRlp0YjRJVyT4+FA/PZ5Pxk6xe8E6Mm4NbMnpnqLLMWarZb9GK1bDmfz7hZ18LL+JlvYqH8n38M7ceayNm7TZYDBFm3DYf9pqzovlyNQ7rqa2Gq2ZCjllMWxb9AYJlvoRMaXJhrC1/QJ2L1jHH+U38mbRySXFbVyjsjQpTWvGLEkvSi7h+mwfR6eGce2IBZHXmHjc0tlHSwQrrFbeljuXThmny2nmHKeLxdrlVMx3jOCzSiU4MHGcOwZ2kW+eJq0FK8Ma1zkrOKXeuZaISCpNc6RYETlcljubFhnntECyQif4SL6Hnw48TswJeW9+Paf5xjT4tYjfCaF8rfV7tNY5rbWjtV5Yl/sc01q/Xmu9TGt9kdZ6vL5voS77eYbWerXW+h9/24O6/bfw9poqvvoRdMXBZ+Z972zmqmcNXbx0nj2h/be4Wx9wJn/zTvV4b379vO8tPX1uscLVb51f/a799r2v+jfXjzzyqvd9reJI/6u/ZzNOJb8uvPLcgqHJT2+ad9/JB0bmfe/lcX7t1SvRffWU+Qt0sqdOzdn+Rmz+8z4R8PtNYYv5r8nL45VEeGZyzK8mmuWrVw9cG8XnfW+LO7eIZCbH/Ovi5joL5T8jfpdTGa9ZpJs9lkQWzy5Zw6Xta5DAtxhg9PLTuKG7j6AocDOabxa2Y2voDgHHBmFcj4eLaSSCnJxt+PdlNnJRzScQpiTWx2Lyc69HSM31ha20YXNzl0Hi20OFJTUVHdIdwi8zG/i7pxdwU3cfqw49ZUZOZYxM4/HAWADFsyyWaZwTBvDJazdQrJhyXS+0jZtI1SUbgleyqdUcJJB2TCOvoflCro9Hus+hIiRjqsaXsn0EvmU66frdUVoQ1iyCmsXeevHAbXeZWYsKBN0ixlcKW02qYoEBSZbKJi4c3cXVI/3c3NXHgXIBB2MXlbXTfCC/gVVOu8ljKsn12T6mVY1rmGCyzm4sC8VlxW0NYOqO9l6suhFtT9dKXDsyYvJSMvj6peiqj0zaJJs9gsAijCTFUoL22/eiBHihhWiKN/Lg1aqDcG2QMGpZtAijFIekgSlkIo2bNCPh32T7cO2IqtAM2cbENqdtHG1yyt7uQsNqycfoSXs1m6qyefiQmW02N9W4taPP6EuIiHhTwPPRJDGlaVaCfUtXI9E83HVuQ3GwDYd/6Opj7F0rcITRZgnQvGdsC8LSLHEyFEsJdN11OwKeXnQmQprS8W939qE0rH1pN24spOjHwbYYtyReaLOx63TiwiKtJXkR592587k2v5mnoiKliRhlQjqEi1tvEKc4GRJIAt8ohDRH8IH8BixH43s2GsOfnqEAvnP8QSoSXCvCCywkcFxGVKsO/+xWSarZmcYxVaY5gpVtJ5Nu8nClYrnVjCMVC0LTbv++8BA1HdKKgyttU1CljYb3dbleYpoGhvMn+Y1IS5MPNBrBiKoxhM81+R5O0THuattEJz4KKEZVTpUmpTIlFL/MbODa/GZcN2JE1QgQNPPqB6VXit+JVMZ/dkxPxk3nF0gGIsMFLkU1VE0xYClCz4B/1+R78IVg0AZdMk9uEFjUlEUF46gwE+PSpqItPAFxrakICbUaoWeE5UcIqEkjth4IQTWwqSifcctwYkfwKdavTiCgFBjlLN+zsYHhqMzfFx6iKsxsZ1XbInTVo6YthkVIrS6WXgocKnJWtrIiNNXQzPTidVukauBQsgRTyiOpQUWSR6ovEZVMZ1jzbaLAAFcJYTGoq5QkFFWNyBcEaF7XfQZjtmgAi0UdsLPzPL7V2cekBRm3iZIwoGeE5nA0zag2riWRFhySIcdq4xwuDzKmfQItub5OtZsMK+DVsOrAnY9i2/Bz1HybI16aR90QIUHEHKMUV3bQ2oCagzrGyKXLmKhbBKlihVpo842uPpOD90OiKY0SUBAxJi1BNGWU0gBedAzoKS3NJwf7qQY2JSL22SEqEgyIsI6eC7p+cZDnQ7OS8IRgUAQIobHqj5dXMnolnoQJqakQEXqShVaaK8a28KnBfqZLcWpYeKHNpGcARQWG4VAKmcBhfCxJse5uHXkSnwjXilCRoFyKEcPYoYVViSeN6/tFxR10p1rxavVZfhgxZEOgBUprxpVHDU2ZiBohk4RsH9tHEFi8GE3z9cJDDKoq+XQbvo6YIqJaM3jJuAUVHRnrrJqNJ+oAOVC0JLe39xJgFBIvGH6Ul3QVH0XZc1mnk0xaVqN9VnXI4fpso1ZxmFAOBV1lOjTpQ1+YzraqjRtOKaqzjoRGaSgJReWEXuXrhYcIfIspS6C0AaUDNIPaM0p0tsW0thmXmmZpcuclaYrJDjgxBjGaK78Y3I2qg5KvRfy3Z2XMU479jnq5tTpRjEMIcYUQYs8J/5QQYu1v+o1YvJ7LszQKg+B+3DoFmZR0KYkdU8i4yQvGtGaZrxHJBGiFEIapcffA47QKt8HZ9YXARdGsjB9ZSUqO/VOp0QDbcIxrSpPprNIxn4eG95JW8GDbeiwEiwOzr4Xx5ctoY+cTAB2WoXmlFMSFxbPjR9BKUxYWqyOHtliNdJNHtqVMR6hxkyHxeICDwJWKO9p7aVZQEpqkGxBT8H5tOLEqEuwrHsNuNk4UyVhAvCUkkQ7owCGOTVJBt0xiJ0zufYXVQiBMVWFv92ruGNhFoCRpZRxcDkwcR2qIacFkVKNDJpAIfp7pIe6E3FzYxspknmWpPCeJBCkr5Lq6PvO+4jGIxWnSxkq+CZu17UtwbMXJbpnlkU1UA5GKN1pUuskjnfRIa4VMW0az14qQCYd0zOePh02OWSRi2G2SlkizgBpJpbHSNnbCdHyrvQg7HjHDhI/bIWksLARCapqQONAo2+2wkg3a4UnadKxSwIbTCjjxiNZkjZ/KCWwECSRCamwEN3T38flcL+cOPsZxZ8ZtRrC5axVpLY0S4D0H6ZQeHd0laijuzfRw7bEM7/CbCJUklgjJdJVZEEmUFsRzGqlNGwEYKk+wrvAEFxcfQsQdVnkRjtBkrARVHZLRhpnTo5vJYPM/OtfhuhHLrBbekTuXbhmn1U0T1ruLZNInWddC7hYx4k0hTS1GluBjdVZEJlIs1B5xDRtHd/HUSWuJtKJb2zQnPPbIKo6GoGZxfbaPQEec7sMCp5VUi0eSCAtJkx1goUgrTQqLhLC5Jt/DwVKBz+V6iSEYlS4lIp6RHoGAJS05PprvIZnySSuNIzSusEhjkRdxctpGAnEiTgoFjpAcCicQGC/AxUFABgelBe/PbyBCNAxb/6Oh0K/6339FvJoZ863823LsZzCOJVtP/KPW+nat9Vqt9VrgSuCw1nrPb/qBKJT4wkhKbhl6hpV+QNECVVFmpPckup72O6d7mElLMPOkxuIBcStiQ+cKWrFRGEfolFKcd6WHxHTSLSrCtiO0NqP4BCEfHu5H1aAkBY8HLZzfuZy0gs3jO/lOYQdFy4zOCmP/FKDRddv7XVMv8MbsWiw0FR1xZf4ChGMzYUnGpObcwccIQ8nf+UkmLUF1ykVaRnA9qoM1P9B1jQTf6DTHlCamjS3Tpdl1BBOaf85sQmnB089kqZYcvlx4kDsHdjEqNQ9XjhBWJef5NtOEfGKwn3MHH+NHG+u6HFrgC0FFGF2MOIKPvXkcX0c4wtz6VssnCC0+ld/MSFhCoZEYTYopoXj7+IP8XvcaCHxqQuLaEaPaJ20ZfnE1sKkKmBqIo0YnTS8ITE4mCAJj1Pre/gRJLcx5xx1OPt/k86vVOogrBYk6XW2VO4X2FSqYufYCtNHqBmMgOkLADXUwLq0lfzrUz1TkMHTxUpLCxkViac1wnc4VakFTbxatBaPlJNdFDlWhKeqAKJDUiOgMNTEtOHL2chRgSYVE8+DwswyJgJiG4Tcv5SYHVCj5vZrRWFZo7ot5uFZEGEoqUy4FS2Hbir0PtWMBVWnsylrjKbZ3nM+9mR7+6c4mKkLykohxz+BufjX0NCWhyeLykJhmkoix+gqwGYsfDjzKrYWdPD9xnF8M7qa9ztm3hCAbKKPH7EmW7X2OZi14qMPIn/pCMCBi2NrIyxbLCd6kW0lqwcdDn9N0nFj9WTLUOsGgLeiT7SY1I6BZOByLEsStiDHbaKj4OuLGwjaWNRlu+6cH+mlRxizYR+GhOTQ5QA2FV7OZqreLy1Qr04SM4TMkQjxh7vExW/PTgcfpsowVWwB80RnnRV3BtSNqOiL+b+vU/t3x3z6V8evKsbXWe7XW+3/DR9+DUfP/rWPvK1hLbR2Zq+7le/Mrxu27c+6y55XAv7XWXHW0GerVr4uWV7hbi8O5Vj5/UJ1/6XWpzM7ZvkEW5tkTVp8+16bo45sGG69/7swFLjt+/Py83/OZe+cqk20cnd/pJqfm5vM+J47Nsyek2uYHzL7XU5mzfeyR+S2WnvbnHt9Tsfmv30zueSa675vfWqq0bWDe9/b6Y3O2lwTzA11/WJvb3r66ZH7VuqUr55KR7k6d0Xj9jjcNz3nvba8A/h3Sc6/fO3Pnzbvv/tNWz9luUfMj1V/S84ORn35ZMU9WzG9RNSTmVuStU/N/753MPe+XqxSeGB9Q3fO+9x+N3wlWxr8z3oUxY31VMSAjtBJs6FxBJIzSmFY0FNjA0LsmJVQEICRCOmgtCJTkdKeNAV1jb0xQrJYoSwOsVITJEXtCMvmpHqJAcml2HVY9V6UCo5ccKcGukf286Bg34fy2g408XYRRbROYmdRxS9PqpvmXwT1EiPqSB5CCF5wYRWGWuaFv0ZaoUZLmXILAYlpopNCUpKAiNK1K4EiFreHRkec5YmuTByXCisNbilvRWhD5RnT/rbmzWdN+CjduzbI2uRAVCTLCxdOKb3T18cuMAb96u1ejEaSVoiThjLbFFIRJpRTDMmUd0C3MrFdpYZT0hIVEcFhXGAtjDbWwQjAJQnKdPhkAn4h9peMEoTTFQUJz0iPPGyAv1KaoRJvvjWlN5bDmWSoUlQtKM1U1Jb8jtQTa81GViAnLYky7FC3QoSYKzMXPRwKvZOHEFX+d66unUixu7upDWpoBEfLXuT4mpM3wm5eyu1bARzFs28QxxyfRbNu3EK0gJiMGozglIhaKOJaj6LBTXDG2hSmpCaoWCRlSiWxcqYjZDq3YHLM1OjS57CiUbIubwqTIk+zxBhn2E6jIOEKntGT1i08ibePgbWuYlhZfdGo4VsSwZSNSMYq2oCqNeekL/hgKmKp3BQGKyaiGigSLRJJLs+t4W+5cErbL4XCCA7pC4BvtiXeOP0hFm9VgueQSAlORSeOMWYYfPmYZBo6nJfeJSQ5In1BJfhocwxOSWCpksp5qiGmI2Q61ikOgJd8t7MCRCl+ZbP17cueTtZK8J3c+j448j4vgi7k+mqyAQ7pKwGzH8q3CdmqeQ0wbjW9XWKY4RmsshAHgLRe//pwPR2UiYfAXgEArIiUZVlUuKW57zVyy/3/JyhBCnA9UtNbzTlFP1Mr4weRRlocWNc9GCkFHaKQKtQ+HhUd10kErI3BkAVNSoz0fHVSNq4dr1OBcYdEVCXq7VzfEgT4+1E8gMMizbUCOnw0+QbJ+6naTxhNQDW3em19PSWhaLTP7O16fCTgIUlZAVyTwQ4smLVhYV5cr10G4gaiMLtf48HA/04T8ftFQfcJI0h4a1wshNA4wHhmh/EmhjC+dVA2suYaiNV3j/sEnkUlRv1Yar2wcUX468DgnOa3kI0GTcHDTEd8sbKdTxPjj4f5GOfuWoWew0IzaZrm9e/QFOrRNi5Y4wqJVuBS04UBLofFQeDpk58g+VpEmJUI+PtTP3ZkeTnIzUJ7i7eMPMlWN0SpcRitTuE4d9AIG+8wKQ/vG6zDuhtiWImN7JE8RnCIStIoAlGLz+E7ygSaXKkMUoUMDKkUIUgqELbAcxcNd5+IJcOJmifLZgX7DLEAzammqkw77oklalPFM1D48N36UI6pEVxiSnPFpdH3OXzhIPXtDUhvZzy8XHkQrQTGq8sVcH18sbOHoYGujM4/bIV4YMOO1YbfZ1JCUSy4+irRSqEiQd1pYkCzj1n31GimUqlEoVALeM7aFqgo4b+gxrhrtJ/P1J/jToX5WUSZC0W6nSdSPV2LEgHaN7MeNhcQQCGFE6Kf9Kl1WiqyI47jGafu2jl4iNFoJHCeiKBUdbpVP5jdTkYK00nhCs73jfJrsgIoO+WZhOxtHd7HMaW+kMrJKYAuLQ1ZEPtVeb4+Sd+TOZSo0ri4SKEQlbis8jI+xMMtqm5LQPGolcYSkPYIT1xwxJ6QkjTRCh0wQR5ITMZrrZfNppeiOzO8ssVvJBiaze9VoP2fKZrSmUSvwWgnl/y7kmP898W5+w2z5RK2My+KnmnyOMgj1pAW3iEGEbbSXm7prRJ5ptNcM9dOuBCKVACFx3YhJz2VM+9R0xB8P91NWPr9q24CnJdflek3JrrR44ZYpgsBiQ+cKQjTX5HvQoZHFDLTkrChOWgteIMlV+fUNHmUFTaAkQ5bGkhpfwJ7Jw40lZUo4rLEy6CDihu4+TtYud7T34ocWX5UWU5ZhnMykXeIobuzuI6MlT1s+U4FLVcB1uV6atKEAXpY7m6hkdHxHywlsV6G14N25843ylzRFCDPqcuU6xe2+zEZG3rIMAE9L0zHUr7kAJoXi6fEXeaR2nIqeXYI6iAZ5f7zOKvlkfjOXFbdx1B+HplZ+kdlIKhZwLCrzuu4z8AOLqdClSwmy/QfRSqNDTehLvMBGKYEfWfWSa4WnJdoLGX//at4ztoVSzQXHxmq2KEvTYX5wxKgK1qYcLhh+lGuG+okCQRQIPprvoRI6DOqakeyMR8SFRVFqWgno/teDrG1fQrdM4AvJkAgRQnM0SNH+rlMIqmb4O+g4jEvNh+ogoSMkFTSfyG9i+YoRnnYMM6McmJRah7YYESHaV1SlJJn0adM2I7bFdUNtXBm08mI1TeBbVCsOk4Q8mj0H6ZgrWqnPuqZUzageZnooXr2Gb3f2MRzG2T36AidZKUIBCSTNdYPUnq6VCGlSGXcPPN6QZb1ncDcSmC7FmFAeV45uoVU4hL5FEBgK3ZhvaJtJNQNgC6qRAa9DHfGh/IU8ljub9SpF0bIoT8Z4zgoYDA33+vDkIPFkQJMIOR5O8414lSqG5XSB3cHyzEJcJD8eeJRJoaig6Ig0LpKf2VONle778xsQUtOsoEWE1IgoaI/9apq/GtjCcVsjgINWyA8HHqVKyLMxgcBQAMcJmfJd3phdyw/aNnNNvuc39T2vKv7bszJ+26h7XL2T3yK/fK2uEQmQUvNumWNtWMUWFjIuyEWCatHFimm+19HHwZUrOWYpsCyCW/7e3HTXp124HK2L0SSFwyfkEOe9N6BLCaQ2uTYpNY4TsWNkH6tCmxiSqCq4ZM0xDjhm6RfXgveN9hOgG9oMy+pA1F8NbCF32hQemtXNJ/ODgUf4yHA/C2SSMhGVvR6JOvMhqz3OGXgcRxhN5dC3WPvSbjoiQavrcc1QP3f5R2nH5g3F7XxkuJ/lvknd2K6iTbjYzRKpNS/aMQ4cbceSimZh3J1dbXSS7Zji55keFmqTlrgvIRGuua0SzcmhR1ILlrTkuD8c5HOXTdPTtZLlsa5GBaAlFV3K4gOWSVXEkVhojtTBp3Y7zQ1/9Ah+vbl0ygSvkx0k4gEZt8aTlsdzp56BkAKZtDgw2E7MCYmU5PTzR+j82QEy2iJphfT/rAM15XN7ey+Z5iq67KEqEQkNZ5830ACt3GTIsfNO4872Xtx0RBRIFiobgaZTxMzAV7VpEi5xLeiPmfNf4LTgImnVAYuVg+PWzUEjs9RPxgLulRO0aMGUDvnRaJaUIDmXAAAgAElEQVS0jPGFASOzaacMQCuBhB3y1e4+OpWgQ9s8t6WNT/hPE4YWXUrwPy4ZIULzDWuIrFXjm34zfmDRhsN9ookj+9rqbcoY9O4efaF+X+Av7jW6Xm8pbuXy3Dks1XFjIFDYxktRiWvzm3nJG2f588/QLBxWtp1MXMzmt79W2EZT2uNvifPtzj5qKJY//ww/0c20aMk+12F5aFGRghHbUCrvTdhcOLqLLivJNwvbOWfgcToijaM1q198klZsbGFxQ2ErH8xfSBRKatqi3UryB16atxS38onBfhZEkv3Fl2gSNlfmL6BDSU5SFmmlmNIBi0SSLxceZGlrnqv9iCiSBAK+E4dNqonHqsdok+Z+ZSNBTQgy2nCgLST5SPCZgX6mdEAVw1zpJYODZoH6P+/5918Rr4Yu92/KsYUQlwshXgLWA/cIIe474SObgGNa61fUxzgxvmLN6uj/UA+x15oFDw6e4Mz7vtF++k8A/5yr/6QhlgPQKmcrjnaPvsATt83exEHbZvG7ZjUW95/wvQ/sWcjpLwPtvnLGLHAzfEJbePHZTKOjfnmk1iSJn3AnnzppLVfVZvfds/CsxutbO/q40lnU2L6to3dOFdSJrhVr7SmWnTwLUNkIrrp0dvuS4myF1Fs9n89v72psH7Vnz/n1dpa/uHvWpqjbTtPbPQsWnaikphHcOTALDH7sWxt4S3GWhPM4s2DpBUGMlS883dhe3DZblfj4w1nG3jWrYdX35hH2PzhrLXWiutzTj3TxhDW7PXo83WDGAA21O4B9Ljjx2Rn/ppdV642LWQB5QRAx+sOjje2/PKFI4W1tQ7gnVNJFNVijZsG274VHGq/PuLzCd+3Zc2n77jP87eLZ+3D1CQDyW9xxlqybBQYXB5EReqrHF98+y7m/a+AxfhbOAr+LrVnFuIMrV+Kc8Jhm05mG4SzA38nZ9w6fuYI/SM222yO2Jh3Nzvkurc0mGK7MX8Cj2VlBoOeXr2q8/ptsX4MPDjAQTtPJ7PXdZc3asG0tHeZFOXsf2oXL8mj2gbnTnX0+31sVfN2bBaY/lL9wDvj31Alt6nO5Xn448Ghj+3b/MK9l/LdPZcxTjn1X/XVMa92ttb74hP23aK0veKXvfHk0t9aIgHTK4xS7haTSXKE6Ea6xe3ISETPuPyeHASeHEvXSIChFPBZQClxqKM6XxokiY8X5ZWYDFpoJaZTEOsIQ4TjYMdMhZ7Sx1bFi5sK/bnwH94sJFgWGova/n15ITAsOrlxpOMOZEjd39ZFK+BQtsJCNVMagrjGka4hUnHOax4hpaIr5hJEk7fh0hBonHmJZCrdeUJJWik8M9rM0kNyfuZAIwdty5/KlwoN4Nds4gk8p4lrR3FzDSUQICS3YjGufb/+8nWbpIh3F+/MbGBIBt3T24Vrm/K7NbybbUiamNG0RFP1pFkQGOFtqtxLH4nSRZsvQMyTiAdN1YBGMLkTaCripbv+0bfg5kJI72ns56/gTLBAxNBrLVtRCm1AYyUnq/N9Uq2+WzPUKP1UxRQW1yEJmknS0lWlSBuzFspBJi/ZQ0ez69LpFRi8/DTuhzG8FIToSuEkj+O9KRSsWi0JBrCmkS7i0RVCpd7b3DO6mG5c2bShuvmeT1IpYU0iixeT5h7wEIXDnwC6krRivlxlel+tF2lCKHBL1PPGesUMcsxRNWnD9PW20xWtoDaPSpJmko1lkt5CIBcSTAa4TsTy0aGqrEU4L0grSStOkQ95frhdFIYjGykzXn743ZM9kudPWKJ2wECwNJQtjbViOwkVwVjyPryNi0qVbxLg2v5kokJyrU2igAwcnEREEFmllZD6/WNiCozUtEZwSCBJ1xTaBYF2UYNp3mZKCCEG8KUDWAeiENnojTjykxfJZ5LTS1lThl5kN3NTdx2k6zhlti3lRlViXOomMthiWii7pNQaRb3T1cXCiQAqJUoJAQITk1Hgn706cRqg1/x95bx5mV1Xne3/W2tOZajg110lCgAQIIYQhTAEyFCqtjUrb2t0iV0UU26kR5Nry2rY+Du2Fy+Nwndqrre1EY2vTTijOJySQEAKZgMyEJJU6p+ZTdeaz9157vX+sQ1UqbUlU3revfX95zpM6Z68z7rXX8Pt9hw5s7utczyLqVEXE9/NPcJZI4EXQqgW/7riSblzSyRrneb0kteJ9J3kG/r7xfzMq45SjUbcZszTlisc3cls44ghytkaVI67ruwgVCIKS4NbMGo44jkl79HaCZdPwbeJWyDdyWzguGobVFTV4cWEzEcZ94tO9A5SkBUoRNOFOeWH88+pTFscdwS/TV/Lg8A72upBzLD6e20BJGAxmWUKl4vGMrZiuxAiEyRd+J/8Yt2XW8sP8E0yrOrpU47zDu9lj+VR9A4xXkWTUFhQn44yVkgzbZnuUc4xQ+4QF1xYeoWDB/flt/E1mDZaMKOkQHcKkZXNgtIPyuEcYSioo7s9vM1hbJI2STUE3iCOpCVCRZFz73JN7iCPTrRx1BUdtzcJ4F4dsxXMykEXts1VNsL53BYNFQ3QdV1Ve0XcxH+hfT0G5jErNfc/pllSKxHTE9szFHNE1vp9/gsnpBIXIZa8dYnkRulRDlUMWP7Gfct0l7gUkhOnaU0IhBeiqz/B4C+O2zWQpTjRcIJxUHHUlR4IkG/00UT2iUbTZ1ncJg45NedyjNm1WwMmYzyQhN49lqU87DOsGZQmjtjmvAtijS1SwOWQZdqBFxKN7FzA22MJ4Jc7/9kzl/+qecwkbFrmGWR1+JL+BZ57sRCEoNoWyWtw4k4TENbxt8RDFhke94XBBQ/PaiQ3Up2xGVZVaw6Fc8ojFAh6QUxRGk1ieNqw8KXhxYTPnu92ESlKWEpl0Z6RuR4MSQ6rCtDDFtMGowl5b0WMliZRgtypQ0gE/Gt6OIy32RUWO6zorB3fyCybxBeR1g3rRQQgYsiJ+5phJYNqSlCUMOnDFqFmBlnTAiBVxzeRmtDBFtuJ4nI/lN3B59zkcthRrepZTLsQYasp+Plts5cWFzVja0KVPc9O0CZenannKwsjJHtFxtvrDvGsky0RzEzKMT66WZFRqhmyHuLA5RA0pBEd1nWOO4GkrPjMp7dHGfWVMRowKl2lCijWPb+e3ctT+rQ51v1P80a+Y//+IWCJgaSC4JP8EANcEVT6U34Dd5fAS3U6iO8Rp0Xwmt4kFQUhfYHLMwnLo6K5gyYg3Z67ERdITRLQIlwfSa3BlxF19A/SFmn7tM/rAFLGWgPdk1tKtbT7XO8DpO/az1I84ZnvckrmKhaHgnGZaY3lgcd7h3SwONC2pOouURbq1ZvQupMcdmbWsqRu93IR0kekUOxZczBnapTXewHNDfuQk6Aw1HX0VFnSZ/LQlNLeOZFkUmhXVjgUXc/tIlq93DbCubqBLvcLDbhecFjU4q7vA+FQSx1GUCHkgvQYbSAqb1IKQM0WSOJJ3jmZpS9X53Ppp7u4bYEGiwtJGxNJA8OTkEXoii7MDo8e7SCZZZXXwP4mxOD2NjeDh0b1YQuBgiCctWtCrfSOwE0/RTkBLW53TRZw3ZFbTlqxzWqLMurqkOukie9qxe2IcWr6c9lSdeCIg0AKr3WFRZNPqNRAJlxUvKZBWigX908iFXdgdFmf6ijO9Mn1BhNVuk+gLuXT4cS6IqqS666R6GjO+fAu0w6d7B4i1BQyGRW4fybJSlpi48Vw08P38E7SIkOWhjespYpbiJXfE6D2zyKLuIj8a3s7781kus7tJdvqsSizkgfQaPto/QFdHhWcdm+sLG4m5IcvbTmN14NIZapIr4gg0nT1lCpbkgfQa3jUS5zyr3bAcWxq4iZA1tNOarjE9FOPcRogXQbZjNRUd0tVVoSsKEckYK+shj/VewjXeQl6vOjk7kCwWcU6XKT6d22gmYCVYYKX4YfPaEAh8rbhEJzhwznksk610hxFp4SDtiHjKZ2kgeVXDpPXOCBucEzRY2dS43rHgYrqkR0ZJ3pS5kkQEP0ivpaXTpFbOdTo4K7RwhEVbT42MrNMizDr45+mrDIFLW3TLGGeKBEtjPXw6t5FFoWCJVeE6ZwGvz1xBp4ILO8/kDO2xrH+CRaFghSzxGj9Fn/BIYtEvPE4LNCujKuc2XYkuooVEpIlrwVMuLNQuHW1Vbui/nLNVnbtfIHupP/ri3zyU7HuEEPuEELuFEN8TQrSfcGylEGJLk7L9pBBifqmpeeLIbwG+nxx+9dSLAT2vzcx77CJ3rgrcc8iG3xStv8P+5ub20edv1Iyfu7V5j5196VwSxM1/Pr9q3ac29M177OR4ThD+VOJjTmXeYx0rT71MMrT51LvEhPLmP6jn5vrtxd3zNv3Hz566YtzFev7veXJ89fzSvMfaz5irpHZ3T3GelrDdPXXbpKXWfzAEmjdi1vyd9R3Rqf8mnfb8BJOT41p//vP7LyepLd7wW9TlrvXr8x77Q+OPvvjHb6Zk/wJYobVeCRwA/h8AIYQNfAt4m9b6PIxL9vPqBS55ai83j2V5ZsW5vC1zNY0mfVNIQV2AqgmspmO2S2SO+z5YNkKanO1XcptZpF26CGiXLi8vbCLdVqVLQWukuGZyM8JzcVOKLm3wzpY2PnMpbWznoya8yJWKr2xdiAaGrlrKqC0IQ4vbR7LGzDPSbBrdg4/m1ZMPsUI5XCraaLtnM0Jo3p/PorWgvbdGpAwd3HI1SgnOCaA9Uedn6atJRZq4Njjlb3at597co+QcidcaslA7CFdyzaTBJauqQSpcruLcFw/4yb+20ovLc4i3u3MPzZBLjokG7xvOojW0aEWiSXfuDaEhDSU9gREpemdmDX7DZliE3JRZTbtw+VB+A6mYT1pBpCHeRAN8IEiiI8FhXaUFm5aOOoVajIRWRFXTWCbNQOp6ITqC3tYKSIGtjRu6iHt48RBPa+pVB+E4yJRDTEdIYRACssUzMLGVy7i+sBG3Q+CXLW4Zy5JI+nQpwW0jWXQEfyX7+Xj/AAfDFOGzs5OgJxWBADceYgnNEj8yglW+xed6B/jHngFz0TVJFS8vbKJLQUtvnZhr4G5BaLHQbqUsDbVZJGO0xxsIYRiebvOytQDXUzgxhZsw7xspgZWQTFo2PSpkYHILHxpLU5yK0eGZAScQkngsYASfI7pKJEx+//O5TXyud4Ab+i/HTSgW4vE3TZjYklg3MSRVAfG2gINRGQdNDEmiM8RLheRszV82hf/9yMISmqqUPN6/iouGthNoI3J06fDj7HYUndbsoDuoKkhgmdWG7UVYQnOmiNPWWqM7UWNFWMfWRmsG4MHhHfxjzwC3jJk+byNIK/Mb2MIiEwqz6g8Nrt3XCq+ZuPhkbiP3da5nWrkzpqcfzm+gX/n0KcHaiUdxEDTqDilhs25yywuWY9a/w7//jPh9Kdk/13oGBPsosLD597XAbq31rma7Ca31864vDy1fzt19Ayx5ai97wwI3N6Uqg1GfO4ezCEvTyBvccfE5yJDrokvj+A2L1rjpWAdEjSHp8kjFVNIbdYeShGcdm5+nr0LXGjSKFjsos9P2DU/fj5gWhtzyldxmGlJwiAT7ZYNbxrL4ZSO08px10FQhwZgtSMdTPK2m+FTvAO8ayfKR/Aam7riCC4/v4M7MOioNh/GhFJOFBEOOzfRIDBVKhm1BseZRR5K3hWF71TxeP76BK7uXkYigOuEyLhRd393PD9NrqFZcw1AMJHutkNUqzk5Pc0RXaRQkh3WFGzNXMGR5BIHFaFTjo/1Gve2Y47A1prmoawkTtkFe3NB/OYeaq8KnwklKdZeAiGfC6Rk0yGglwbgFFWyGVAVUSEnbVCsu7cIQLIaHWrFFhEYwsddDl6uEI2WW7tmD1gK/YfNssZWoaObmx/tXoSt1isUYf1rYNIuoCSMmpU3Ndxi1LdJf2kVYhuJknK92D+BPgNMUNZosJBi0TYpKR4JxaSbCVBShiiEv6l1pJvfI4ohlbKAsGXHleUM0yhbD00lWRRUO2WaAaJRsjoclvto9wNtHs9itUGk4TDdcSr7L0/VhGsIgc9RokamasTJ7LOZxbeERVN0QQg6OpamWXBplm7wwGhyNEaOaVxaS+zvWcTAocHFuO0JodM2sVqcrMRJYTKs6Q02BrZsyq3nXSJaj4TTTo3FqRDwejPGq/kvYW81zICrx9/ksE7kknpC8anIjJRT1KYvRYy30KMGD6au5u2+AQEuGhUfRMqnCx/tXsc8fw9LG13FLMMJwFKNRtvlg/3papUsgzOTtVyymQpccPpWKx8FaC+smtzAqFU+EExzVda7pPZ8jdsQH+tczpOJURMS4ZXPriHGSf8IJEFIzYVmM1+Lkgmny+JzWFJjqjnxcFIfsiDU9y00dyfb469EsP09fxQfyWYTQ7AuN7vWHm8Jaf2iE6FO+/WfEC5Fjvhl4sPn32YAWQvxMCLFdCPG3p/ICoS8pCc2zFywj1YRfjFgau8vMylYMpKNp1RYJHVFurqixPSw7wosF3JpZQycuqSji8HTe6Onaaob5d23hEUa/k0damgUiTgc2nga7y6Mm5Yz2bkpFtEQR/5wzK1Vpa2IR2K7irr4BYl5AawSFWpldxSMkTjhvwnH4dceVDGJEbbxYQBgZkocXN+4W7croUwjMRWtro2z37c71vFf18JaxLEJqPpnbyPCLlhLDfD8rrnFiZrX/QzFJSgsEAmlrXCzuzT3KG8fNil40VySyqZ28SFmEkcLRxpA1LRwcJG/LXM1Do08Td0IK2qfPSvKX/ZfNqLMJDM42JixwXF5Z2EQsFvDPuc1UUXR1VYg7IRaaVFcDkYwhUw7PrDjXnB5X0W03EK4pQHluCJaF54Tc27kez2miBOKOQU444QwhQrpm1W1pcNo0CM3ne2bziwltzk3YJDLEiOj58SEO1UZox8IWEa1aMjrWghBgp8B2DfKjI10lriUx/ZxQklmpm/eVbLUTOELT0MapZrRJmdf1iLgd4iZCAgwq4x2H2qigZiCLTkwRx9QJrLhuSlia1x7xzTY+V08gXAvZRKoIoBQ1SDY/j2q23zy2DyE1PprT7TYWiwRSCH46vJMP969Ha0Ff0w2kQYSTULiuKfBOSptUZBAgnZFRL3y8fxWhktxsL8Zu9o8uK0EHAV4qpCsS1LWaSdXZXkRMKL6R24LnhJzhVmb6Rb+Vokc0r9Umwj2hTalss+tzVzMXnMBItk5bghY7oNWKk8LigDC7hrzlUhI2CS1ISQ8PSUPA53oH0IgZLsESe66Gyh8af/Q55t8WQoi/A0Lg3uZDNnA1cGPz/1cJIV40z3NnKNn/MjlE2KQd/3h4Bz9PX0VCC3SzYKHqoBqCURFwZmfBiNMrBdqoeDXqDiUUO9UkZSlZll5EIfBYsD7k8z0DlJvqXo2aQ1C32BNNUyXikK3o+PrT1CX8mzInviGNbsSbmoLrjbKNEmb1HQmjdzHUXLSfmepn9ASdH93w2eS5dOBQ9F2qVZf7XJdh22jbBoHFXkfxUMdqfCH5X9WnGbONj95rJzZQsCy+1jWACsyg2ferQ1xbeAS/YfPY9n7KBY9xoSioGhPCsN78qsV1QZJr+y7g3s71+A2bb1xaZkoo6oFNItLcNpKlogx64eZXTjJNSEn7TOuAn6TXGI1jbRheRe3Tjo1GsJEp7utcz6SqQd1U+atVlzdkVlOMfMpFj1pgU5A2Y4Mt6HpAVPTRkUApgdaCQujxJ79ShGgqNRdda7DoOqOBHSpptDIqPg0hqTRcVqYKTNywjKBkmJI9yqy2o8AUN31lmG3DliaoSerNSydvmUk8iAJ8NDvtOEPCp6gcaoFN7OolhL4R11dK8LG8Qd2EDYtQRwzbzUHaN4qG09qc5HZnFvcd+RGfbCoFDokABRwLpmcmQhVI/KpNgGZ6Is4zuzqJR1BvcsGXxEwOPBCSr3ynhbqQZpeDZq2bodScZMai2dxqveEwoRvcl9/KEV0hjELuyKylLDSFWozJpuziRFRHNSQ/bHQgMc4gBcu8d1HYTNhQarhoLfiGOk4A/Lf6KOOqyjWTm6lNO9w6ksVGULDgtsxagrpkEpcbM1fweD09o09dRDEaVZkgoBQ1OC+K4QtNQVqMNzOXU9IsdMoo6lWHNqXxlcVfyn4OqiLfyG3hxswV9CiT1kpowcbJvTSIUMLs7B6IC6Ob7tvsD8yK+YXK+f6XRWUIIW4CXg7cqLV+7tMfBzZqrce11lXgJ8Bv9B0/kZL9V+2L5hy7tvDIvO+7o9A1536xOH+h4ZmfzS0iLnpj1zwtmbGIfy4+ftb8Rbvf5qFwUX1u5uZ1/vwFljcnl8+5f/PY/PmzFYvmWiN9+OWzhaTvOXOLSq/ZOj+s6K4H2ufc/5A9Mk9LWCFPvcjU1lmd99hPB+Z2s4Pfm/8X3FrtmHP/ZYWH521re3Mv06lb53dQLv3kmXmP7ZqaS164oDF/WeSdjbmf/UfnzNuU08+ZW7D9VHy2WHnzK+eq0m0J5j8PJ1LnAR4L57fQvJa5fcH9LVKZX5IL5j32nKzqc7E0mr8w/d6T8r4r1fz971+ioTn3d3rzK0le5r8wbiW/Kf4rFP/+QwghXgr8LfDK5gD8XPwMOF8IkWgWAtcBe57v9c47vJtWbVZI56QX8uH+9dyvhojqEXdm1lEe9ZCOxkFSkYIjtkZXa2CbFcBENcY/5zaTljEiBAW/xMsKDzPSiBMI6AthwrKNg4lvsUAmOaqrdGqLwcvOJh1GPNx1OVd2L2PcMopoHz9orIjO3v+0UeuqeTNSiIkIepPtbBs7QCqCGzNXsLp7Ge2f2kqbCGnTFgFGL0JpQaJ5dpWS9DQVul4z+RCpprZzRTnc3TfAdX0XcdN4lmrF5Yu5h8mvW8q9TQcTAMvSDOoqdeVz9wPtJveLwTMvkkmOOyZ//dDo0xzTNfymbOeH+9fjSIsATY4GLdgkhcN4VGPb2AG0FiyUCTRmJaHQCIzF/IwGrpB8p2MdUhpVsHFVJQib7jFSGC2PSh2koF51qFZd/IbRx+767n40xs1FB4pAWabIJzW6WCYqh0itqWibt4xljd5GQ3Lh8R0AlAYdgrrknr4BpNBMo0hHgqBmMawbzXMS0f6Zx8mVJ/lkbiOLAkUSi4WtJYqRQ6NkI4TZnWwudnFnZh3jBEhLs6Sln/cOZ3lPZi3+hMAhok2ElITF/uJxQ0TCiCtVtE0YSgKMbrVWgjHdYGPnFQipKU7F8NFEkUArQUVCRQpTJD6yy2hooNGBYswWJKOIzbVjbB3bTyQMI2/In+LB9NUGw9+UN7uu7yLSwkMIybSqMUVId4s5//c00wZB3cK2Io7aEV/uHmBEhCghGHYkZWGsnSIt6LATHJMBoZYsttv4etcAtmvO87Aqz+Crq0WPhFZUdEA5clBIPt07gIMgLmwcBC1NanU6knha04VDgJEluLJ7GUUd0qjbjNqCkrZJW3EWWEnekFnNvblH6VBQlBbTUrOibTETmJ3IB/rXY2tmzGlT0phgfPikBdTvG3/0xb95HLI/B7QAv2g6lXwRQGtdAD4JbAN2Atu11j9+vvfYs+R86mikpemwjVbvtrEDyJjkrtxDM64jOW3cFhxAxGIIy8FzwhlIUELYTFuwLLmAB9Jr6HFrDFqKqjR0bjyXWEuARtMrYhRExKLHDhAJgS0jNo/tIxRQk5LPNgWMDi1fzoilaYmZAUBKTSDg4pYzAChLSGLRZSWYevdluJbiY/kNvKzwMF0dFeO4ERk9imLNoybMBX1f53oGpUKhSVoBGsNaA0i2NHhr5iqEbZS3tBZNP7mIFaKFd1tn0KskjpCowAjJJLBIauNi/YbMar6b38Y1k5vxIk1MC/YXjpPSgh7MoB/Dot9K8tK+C/HskDiSaVVld/kYJRSOMPoZAC2WB1JiYYSmHARbxvYRjwXUsAiEyfeKljhd393PiiO78NzQMOQsm7Hrz8IC4pZCxF0sGRmZzZqHiHtoX88gcT7fMwChxk2qmftuQiEtzXuHs8QcI4Tz3ibqBOD9mfUEwjz/JU1H5wDBBAGWHZG2fJ4c7EFrcx6WqDrdkeSYKiHtiDO8Tj7dO8CgrqEjQYBkWtt0EZBJdDLapCMLKQgxbMKztGdIPp6mpkMcGeE2WaW7g3FcV2EnNUpAvJk3f2nfhahIYGmNiLv0BREtWhE0NZMnCenB5cnJI7ys8DD5sIQUmm4ZwxFGfrOhfJa7PVgILNsMpu8dzuIKCzehsO0IVwuecaIZadvT/JCUFtgiwo8kFpIYBvGTFDau1tQqDu/LrOPpqaM4TR0WaUVUhEUMm7TdwBERqcj09x8P7yAXVVE64m2Zq3nfcJZWHRKiuX0kS04EjAZFFjXRsl2hUQ8MdUQSm7pWvCezlinL5HEP6xpbx/aTLZrFjgQ6opAqilpo84uR3TTEC6fB+Ue/Yp6Hkr1Ua73oObcSrfXbTmj/La31eU2H7FMq/jXqDv3KDDxbxvbRGhmrH+1ro7i2wEcrQbfw8LQmHQnQEVoF+KFFW7LO1T3ncjScJgKEMDRTX1ksVhZtzezC8W9NoAIxgzzoiySjL1tKSc6ecE8zUwj6cP96lu7ZQ1kYCyswPnZVoXmwOYj+fT7LmG7QI2OImMPqscd4f2Y9j/ZcilKCKd9DCVN46mip0aqFIV1ozVJl4SDwbEU6gm93ruer3caM1WueGgeN54SIZiHv47kNvGUsSyjAFRbxNrPtLqPY07RX6m5CmR7rvYSyJekNYVnapIs+kds4A706Q3vc2mhBa8Fncpvod9o5K9HPl3OP4MiImtCMWxY/H94FjsurJx9CRZKSDnlt/+WMFpNkvCp9gfmBhWszccMyHum6HGlpXFexNpPHanWYEIqassAPqYU2X+8aoCddBsdBuAZiJdCsomxEmIQxRF0YKCwvQkj4TO8AjcCmokPu6RsgCiUl7XP7qiHSkWLs+rP4xchu3pS5Ejo3+EkAACAASURBVK95DqeLcSrKpiZNfnlSuXzSbVATRhpVCNhVOU5awXfz2yhNePw6bpFA4UnFwakhYliklUYkzOPJVIOJJqPxLftbaJcujq0QQpNM+fyF7EdITVgRtCrD/Lu/Yx0OpshclRZCmjx7XIYcns6bQRtNCTWjhbHS7caxI76W28L3809wcddSRipTtAibL+YeRoUSieBzvQPUtUIFxm5LAK+zpmfSEXs9m1YFayceZWByCxJmJt0ObGNf1uLTFUmqQYMOBQ+NPU08FRDTEVGzD4ZaUJIwRciy9CLOlC30Wym+mHuYu/sG8JGUULyi72K+nHuEZ6ZylDAFSQ30OjV+PfIkLUgsBDEknja7nYo2fTdXnqQioSMSCDSjUY22WIM/61+FpzXvz6w/lSHleUM1d4ancvvPiP8jmH//PTQWMwB39Q1wQdDgtpEsMmHREQlq4xZ2UtOnHS7uGqMmAMsi/NaXaU/XKJTjPDy6l14rRTKCoqpzfWEj5/15nVtHspQsGPmTpVgyQkeCV/RdzCWha9yVy3D9JYNsESmu6T2fQMCrmxjQarMY0xtZBKHk/Zn1ZJYY+m4m1cGLelfyqv5L+F7+caZ0QNvdjxhHZIxL9qZSF9+NMyO4/0S5g7LQ1LEoW5IvBM+QiAye9E8W5JBaU5UmZfH1iSdQNUFNSG6ojXJwsItISV6fuYJbMlcxKiPKkU+jbPPtzvUcV2W+kHuYjwu4c1WeOzJr8ZVFXxhSsIxWxoTUFN5xMSO6QR3Fh/MbSMmA1WOGWv6rkd2ca6e5MWOkTgpC0R+GXNt3AXe/eRPf7FpPa2udsg64SCdY0FWk7Dv8W9xn4aMHiUo1dD2ipiwsGRGGku3He3n9LzyWKpsIQfqfdnP+wAQlC8oVD10so33NuGVgiQkvIJwKWfDIIa4Y3caYbaEj4wc5Lc2K9xySZAKN5UQUowZf27aQh+ISYQs82+Gfc5vJeFUW4tHaUue47fKyW220hjNaDfPP00ZWUmtYnTydN45n+VD/ejpOr7FISaSAoSjG+zLr6MZhyBaoqYBPeDW8lMn5vvxmn04ZI4mNFJr/UWpDKcHtI1k2lDs5esjoXxQtGHQkg8EUoZK0RSG33C+ZsgRj2uPV/ZdytUizNHKxERS1cZHe7Y/herP55VArvto9wJdzj/DWzFXoSPC3IiAWQZ+MYzmae+pJJFD3be7qG6AuJGf7xvj1OZH5FuFyScPsAHO6wde7BvjxWB91YVbKArirZx1B3cJqDk5P+61MSgcLOEO7ZNx22rDY54/x5e4BfAFJEXJATSOEkWhd2NLFGwPfTFIC3h5N8pneAfbrCmeIOE9GRTwNSUJeotv4QP/6mb53jVvgLrfIS3Q7KpJ8P/8Er5l8CPsFGicjrU/59p8R/0cMzF/smO1820WFZ6xZttfJQm7bxmfZXc7r30atMls8qJ9UJDny49niweZtGfpfN/vcw/bsJuVn2xZytZhlcH2vY+2M8DuYVfRzMfJs64wAO8CLolklMICecPYzvLhnmJv82ftX9w3PaXuDt2Tm70eO9fNlpzBz/6bOVTN/f83OcOEls8+to7hz3Wyx6LvuLFPt79Dc+vhsAW3MmsuM/ND3k3Pur514dObv3uTcwmCPnn3u+76yhs+JWXumE4H+Z+s4x6+YZUouOW1uYevrV81+vql3reLYlllrKRGfy+x7sjr3M5x4WZyoLvekp+cU/15UC7FPm1WtO+7PqtQtUXWKP55Vl9vSPdeaKX6iulxNcLGaLZucLMx+W2P29/v+P3v8j9NnC3HvlrMFstX2NGeeN1v8u20ky9fis5CvL71sFnlR0QH/Hsxv2/X6zKwm2Adqu3hV/2yR81vMtel6b2z2t75zODuHWfenJyjwbYy5PNY7+zrXL5xra3ZiQW9cVTmT2e/2nEP4c7HBmT12ttXGOj1bNP6qM3t9fjrq4d+ZLWKfIZNMnTACnViA/07Yzq9HZhUL39xESb1Q8V8aLvdChRAGZ7f8mScp6YCKnC1oRICTUES+EZmpSUFSA5aF1oowtIjZIW/OXMmZMoWrzcoCYKrmcVffAC3NVEbbR7LoSJAUDtMY9wdpG6t7rcEWZmv1qsmN3LG/i3Q0+/PEXINdVZHBWbY6SX41sps2pbmu7yKSwmbq3ZcxcO96Xu7XCbSgMu3RlqojNWhtNJkV0OXUuXksS4iBsj3UsZpQCFLS5V1NRlsKa8YZWghNUDI5xQwe38w9yhc29LPAMoOEgyQuHb7dabCtMWHxidxGLGFKF7ePZFkU78bR0K4tHCHRaN6ZWcPq7mVs6b6MtJZc0nIGv6wcZiyqYcuIuDZwKwsJUcTWsf2EoeRHw9sBY2PUFmtwpq9Z+OhBhC0RMUmjYlOruTiuMqgAKRiVmhY7QEeaUEkW+YpGYEOksdpt0krhCkVNCqQrGLzsbMAgYLQyW/TbmxKRx0SD7kgSNiRdlvGiqQiL4PAk57efzjsyVxMhKGMcRhSCHQeNXGzDtxFCUxKaNmyCusl3grkYSqNmokjYAafZVfpSacoog3nvcGkgCBuSRcrijeNZpKMJmplI246wLG2KlFITBaa429d0W/9sFEc3J3WRcGlXmklL8tPhnfTaZoK3EbQKlwSS7eOHcL2QsLlq2z3xLEGkKEY+DhLLiZgk4C1j2ZkL2bjkGPEsMIuMUduiNTI53kd7LsUVEtHs03UUbxzP4ldNRjrQamaH99xvd5rdgueEvHZiA7eOZIlrQZv0qBKxc+Iw9+YeJaEx9lNEONpM6oOlcVwkOhJUpbmWT7dayIg4W9UkJRSnBZqSsGmWkVDa1GCmheJ7HWsZtIyOdi6q8ZP0Gj7yAhX//ujhcvNoZXy0qZOxUwjxcyFEpvn4eiHEdPPxnUKID57Kh/AbFhNSc/Dc5TR0yG0jWUNVdo1NjbTBai4MWlVkTqJSCNvDkhExN+QrTdIDwP7p4/wsfTXt8QZ3DptUxqsmNzL9wQFirQGxprtxLAJ3oUu7ikgmfWLCJqWMWMu9uUfpUfDMinNJK0i0GMU224pYGEAprPLmzJW8fnwDPx7egUbT/r8eA9vlV04c1QTWT5VjtEVQK7tYtpFwrIZmFdGnBJ/pHUAIUyTqEh5f7xog3hZQQmHHjVxkKuEjHY3tqZlihKthSFVwEwoB9IkYr53YQMwLZsgxljRkmbv7BqhGDfqU4CP5DUggRjN1IF1sy+STW4TLZYnTmFZ1aqFNmzKWTQ8O74CYWYHadsRNmdVc13cRrqsIlSSmNUdXnYOIe8i4w7JDT83A59plgNXiMi5CgkgibNksoAr6+oqQMJDGSEBn0hR3rS4PNx3x1OkXEI80bqdGOpr/3TNANXSMxKWGRE/ISlI853fb/YODPD5+kF5tk9CGjKOUJGEHXHFFnkRniCU137RjxBB8MrcRNx7yYOEpvt41QFkYEg8YlT6tBeclF9GnbbqURqYT9Dh1pKVnBi+7VeAhibSZPKQVURaa1o4aVtxQ7h2teTB99QyNOSEUOoxoiRS3jGV5U+ZKQq0YlxGfyW1irUpwV+4hMqkOnJhiSvu8IbMaAEdanGalGNMNLBnRi4GmRYB0IpY/8yRn+JpBNQsVlRosDSnHRwrNN3JbWBwK6r7NhaR4IL2GeFuAo43Ea2dTw9lNhCRFyLCqEkWCx3ov4Ztd6xkVISNhmc/mNrGu5zxe2385dwxn8WyFixHFT2g4J70QD4EXD7C00e04okr0aZtLrTRnao+cI+gUPkeaO9gOYfwBF0Q2Sa34RG4j8VjActlCSgYzC7Y/NP7oURn8Zq2Me7TWK7XWFwIPACcOwJtOKAp+5FQ+RFtfjbWNBi0Zn2VWGz9Ir2WJHyDiDm8Zy+L22VjtplOf4VZYHtYhZUbqvhVl2nur3NU3QL92eeN4lkYYcNaicVra6jyYvpqzfZ8nF19AJTuIndR8LbeFSwOXZKTp+OYewzqLhawQLXSpkGsLj/C53gEWhj5LntpLvOnt9k/dA3T2l1kc1XldywouCz02dl7Bx/sHWKXiFP/hT9j/xu9zZgC9yQrpBRWeJc4SVad3WZlYa8DKesii3ike6bqc5WGdc/yA/p4iC0Ofm/yQN45nsZyIz+Y24S1J0N9apqWzjpWAWLvi3KZJ6VI/4gqrk/hiwYU6warQ5Ztd6zn/6C4K77iYz/cMkO6o0i0aLGsozvF66A5N579UxTlTxLkgsPlsSmPJiGW+ZLGIcTZxbhIZ0ok6mTCk5zlhpSji6TNX4sZDunH58fAOEq0NOrsrdOAT71OIdBvprz5Jbs1SYm0hnYurtMR8oyinHLraK4hEnKV/adFBQKw1RCTjWN0pFrpV4imfgdOHEHEXGRMkWhucYVWIqmC3Qk+oWHLGBOcGFreOZJEJQU4EXNWoszIzRuHm83lPZi0fym9gQapMZyToPq1Mur3GI1szWClBa7rG7e0TLPbNBZfMhLw0vYIlVLm0DrHWkOEoxlXjW+lfOI1Gmx1B1AAhaW+tEe8KWVk3KaqPPNFHr7ZJd1bpWFSl7XSflQ1NrC3E7rBYouqkdERvvIqDoKurTMINkC1xYs1pVqH5xchuLm4Ivtw9gMToGV/Xei6Wo1lHO104/EX/peTKk7Rh8538YyTafcYJ+GF6DRcpD7dLcHTVObhazxQ/F3kVLpAlzghCkkmfzu4Kd2bW0aoi0h1VUlrQ69WwPM37hrPcmllDv/KNYmJ3SHu8wYDsxLHN4kVquCxw+FO7n8/0DrDUbuPb+a3c17meeCxgVWgURDKB5i9iS0loSUvG55ygQbqtyoaRp+gLYXVNc3qgeWligvZEnXU181vEkfQHIcsbIfuaIvte0xAh5flz0ll/SPxXQGX8Jq2ME1HsSf7zUjH0PDi/Zf3JkXrNylNue8P6+e3uxzh1XdiBpUPP36gZ/+Ke+uu++Jb51cjSX9h+yq9zovPI88V5h3efctvfFlMb51fGOznC6NSzbdaS+dUDe+Spq6Ot7J6fwHFyfPDS4edv1Ix3nHbqfeG3hf87DBfPSen+odHSdupKb+c0Tl0pr1CcX0lyjX3q/eR3DUV0yrfnCyHES4UQ+4UQh4QQd/6G4+8RQuxpZhl+JYRY/Hyv+Ycw//5BCDGIoV+fuGJeLYTYJYR4UAhx3jxPnxOFoSQbPY/icY8ngjEGXYvDjkMwWOHuvgFKBzRBzsBpjvpJtjsxKJfRTd3k4nic7aLCA/4xPtHc6uw63sPQcBsHXYeHYw7nH91F67v/neqYzd9k1rDN8XnWNXvgaWlRnIqxKRzlkGvzYPpq7tzUOTNjD7qSYjHGW8ayTI/F2RBTPKEm2WEHbHHiPC1qbLfqRJPT9C4q8frxDeQqKUaPtLJvfzf77Bgj+1JMj8YZcmzO2ruH/SLBDifGYzGHo8PtXFt4hJ9VDTttejTODf2X03i2ytFiK9OjcRoTksqYwwHHdJTPf8NlezSFP6w4IBvssAOOOILH+1dxS+Yq9tkho2MtHJJxco7FE5VjPO2Z77tFVtkeTbG7qVUxVY/xC7fGhmCYjdE4e+yQC4/vYNCxORg2c0gNk5oYybdwUJcBOD7UTn64lYe9GD0/PoQuV5m48VzKox7jR1KMHkpxsNaCKlTZb4WMFVJEo1McPdrBJA5Tw3F0sUw4VOS4n+DocDs/PraAcKhE9w8OcubufRwQCRpFi2rOYtCxOH60feZz14YEHdjscmI8M9RB/eFn+OqkGYgOVtrYb4XkDrdxeKydQR2ndNSiUbNZumcPe5tz4PQRl19O7+VpmeCQJ5kcSnBktJ2fpNdQGE0yGVY45AqesWL4hyZ5dqKdiWcTlKTFD9Jr8cc1v1SjFAtxJgcTTB9x+WksZPiZVsJxxT47xlHH5uLcdl5+UDE9FefS4cdRw1Mcawq/17Xiyu5lHHMEt4xlediu8fbRLD8q7mH4WCtDMuSTuY0khc1Z7QuYbELLxnMptjXy7PVsNsky5SMW06NxDrqSfZ4paN7XuZ6hIMFez+a8w7sZyrdxVNd51pVMFRLcMZxlT9jC+JEkH+0fYEc4wR7XYyiqMj0YY7iaYJOe4thwO4cK7Rx2BZucBg/rAvusgO2+KULfMLGBsWKCA7YyBr6O4DOTj/Gx/AaO72ljn+uRn2zhnPRCdjoh1xc28qirmFIux8ot/Lw5PteI2OvZvLKwiYmqwUCPTaQ4EJV5tt7CZnt+BuLvEi/UilkIYQGfB14GLAduEEIsP6nZDuCSphrnvwH/8/k+3+89MGut/05rvQijk/Gu5sPbgcVa6wuAzwLfn+/5J2plLD+8mWdFg7P3P83Wsf28ayRLSYLVbvO+4SyxDoXdZTrabk8wYkWIdBprwTJ+3XFl08ZdsHPiMMNNjr7UsG5yC0csxVlNhm3xU69CCGNk6RPNMPmeduHi3HZeRy+3jWR5WeFhprTPrSNZ9i1dwR3D2ZmVhxCQ0Q6/HnmSL+Ye5n3DWe7NPUoLNu2feHSmyNRm+ahIMCUcxixo6ahTqzm8fTTL4/2ruHksy20jWf4+n+XFhc18vmnFA2Zlel9+K3a75OWFTYRK4iQjhNTc1UQJHBcBMWGhGpKKVkxqs80LleTLuUf4bG4T+SjGzWNZ3j6a5VhxlA/lN3Bj5gryUYWfDu/kM00SzTWTm7k39yhbx/azYeQp+rXNdzrW8dejWaaannui93TAuGAcC8xKpiXmk3ADzvI1E3+1DNGaovPevU3J0yqJFp/lrVN03ruXz+Y2kXAD0l99koNWjNdMPkSp7CEScazOOFtjxuVjxvliYCm7F13IqAWJhREqMA4tV41vZbBJNg3qFgd0hdtGsrTYAY0JyVTdoBISWvG0KtDWViMmFApwE4pY0nSGj+U38LH+AYSA8WqRhoB9ok5LR52KsHBRNAKLnROH+UA+yxf0IN6KXvK2Q7KtwY0TG7i+sBGtBJtG96A1BL6FE1N8OfcILW11hAt/PZql2LzKdk4c5pL8E4Zpt2wRbxnLsqX7Mr6Tf4zNY/t433CWxa29fDP3KOt6zmO4XKDkuzNkp1+UDnBwamjGi7G1vc7uiWepCM1389vwWs2E9bXGIfxm3v2ACwXL4hlpvrclNPflt7JJFLGtyIhaqZDzj+5iN2U2je6hJuBHw9vREUxJm3wwTUNLFsQqTAiFT8RPh3fyhdzD7Bh/hlf0GdWFrW6MUXzu7hvgfcNZHGlxTe/5pDurVARM4bC/cJzHmvTzz+c2sTNm8/LCJuLNoWhHME5FzN2AO5biR8PbefXkQ+xqzE9d/11Ca33Kt+eJy4BDWuvDWmsfY0J9/UnvlT2BIX2iGue88UJYzt6L0cT40IkpDq31T4QQXxBCdGmt/8PeUGv9JeBLAEcvfrH+6WiMr2HozQNBnPuZ4pZmW1UTyKriA/3rWVWPmLIsdLFINHaURb1TDI60k2xKZqypRezqu4DrhzeysfMKhhqSZKTMCuhbe3CTEXdk1mI3gfnvGsmyqhGxe9GFrBzM8oP0WpKEvDi/mX/qHmDZoSz/2GMkIT/eP4CQE5zdiGhx45T8Gvd2rucJL+KTTTD/acky93gDtDgFkm0NvFIIJQMBa2uvcY8eIFRlHkxfzajlUJZwpTPNUw3N/R3rePXkQ2zPXMx3aCGqD/HL9JXE4iXsdoEXKO7MrEMiSGlBTUT41Sp9wmOSgIQ2A+cH+9cTAQtVhe91rGXCsvgqeV4n+6lEcLaMMdC/nrLQ3JN7iN2LLuT+sJ2fhDm2jR1gVCjWygaf7h3gnU0khB49xpbuy+juLvOpqU7O7u/E9WqowOByo6pCT04z+aYVFLYpSpMxbDtiophg4oZlfOKhPmJOgen3XsnID0f5YbiG7p5xdD2FrgWsrmke71/FIV9jd8bQYY2Vgzv5ZfpKoqom0RnQOgpPLr6AH/itrOofINk9yOXjLby0Z4CJIOSsRXDj8Su4N2cggK8Q3dhenvZ4g+G6ofUXJ83S7Jtd63lCKFL9PjdNrebWXHbG47AuJAtdn/Z0lcX1Xt6VWE6ngqgwydk6RqQEH+xfz0fyG7j9aDt/1r+KUAnaW2pIS/PR/gEsJ49s7shWNkwe+F/jAX+fKJOfrKOenWjadlW5ru8iLCH5E9XKO0ez3JK5ymCF+1MsbJ3m1d6ltAgbF8mXSkZH5rbMWixnlDsya/lIbgPvyawFcsRTPn8VLuFV3iSp3gH6fM0NE1nu7VzPzf2ruCS/lb/ov5SrohTIaVqVGQSOXXI2pz2+jZf1XYTXZP65iYDTp6uscvpY5JaYKsc4V1o4tsef9a8iI+I8G1X40fB27u4b4Aq/TuTF2S1rfKp3gO9Gea6RXURqhFQEC90q63tXsMrqYBsH+Gj/AOc1FI90Xc7uUPLa/suJC4suZQhmI6EhmMXdAm/NXMVr65prJjb/oeMVwAuJtlgAnIh1PA5cPk9bgDczq8Y5b/y+Whkn2ntcD+xrPt4nhOHICSEua77+xH98hbmx5Km9TFvG9kZpzRJV589VO7pudF6nR2Lo0KxyxmyLqgRdroIKkZamL13isXqOv+i/lHHbZqk00KMLbpYcdwTjtk1RWkwOJwkbxlopwihYFd56AQGCTY00r+i7mF/GNT4Wd2TWGi3nC5YxYcHDXZfPrLD3e5JrO1fwhsxqGlLw68bxGUZSPBHw3uEsKwd3Upn2+L7fwYgtkbYmP9pKQ8BkEMNH8sbxLO8czWLJiHik8YXgxswVpLur7IqKWCmbI7ZHpCQHHumgMuHio/m5P0RawWhUI7Ug4IiuUNEhfz2a5eGuy7n9ukk+lt9AGEkCjEj95rF9lAVMS82v1RhHhM+gNnlDFUkU0GklWNDSSaypqfCMFfJg+mqu6T0f/Dqrxx5jeLSFEiHfzm/Fau5OjjkO3T86CDpCCDFDwBgaN3hWYUsUmvOP7kL7IZ0Xm+1urexCqAiGfTPZasF5qQI6UDRF06hggwS/bPH20SxhaBlavobqhE0koCoghiKqRtybe5S3Zoy57VEZUiu7qEjwp2+HWsEhVJJDy5czbglyuk5jymIkqvPV7gHujfLEexSHXMFII85UIcHR4gjbRZWyNMzGD5/gEH1f53pKOkBpzYQfw2/YNCo2YyKkWvQ4+ngrX+syJI9XFjZR1SFBYOHKCFyboiVQWnCgPsoK0cJO23zpSe0zLhT7gnHKJY/789v4Wm4LX8o9wlntC1jc2suncxs5Y9c+9kQlvt5lJhRpw78XetFAGBpInKs1X+saYK8LVpM9WtYheSvimskD7HZCAgR+1eYTfQNojOTAZFhBCAO/kwg+4SdJxUzx7/TQQCgtBA8O7+CD/etn+AbHRUAHDg0BARE+GhVI2pXGDy1uUt14SG7MXMGg8FEIrhrfSgRM6QZlHZAJIjwNG7yAp6kQBBaDUXXGNOKFiN8llXHi7r55e+vv855CiP8GXALc83xtf1+tjLuEEE8JIXZjxPHf3Wz+GuApIcQu4DPAa/Up7AVOjoHJLafcdslTe+c9tuGf5m4IlrxjfuuhNV5hzv1PnKSudWIs9U/9K706MX8h6VO9c6E/v81m57Qz536+G26cX80t/U+nXqS7MTO/oXmbnqvudV3fRfO2HX3Z0nmPnRxHH0rMe+ypcnrO/aqcv4u6iblKfu7ZHfO0hEc/f+oFqcvq86vLvdufqwv8lTPnt6FatHJu8eofEvMXIDeFp25BtiIxf5HzutjkvMdOjl93nH3Kbd/UmD/berIG3HOpl98U959U0KudIIdwcryq9v8dzeJ3Kf6dqITZvH3phJcaAk6Ux1zYfGxOCCFeDPwdRvjteSvRv69WxqubWhgrtdav0FoPNdt+rqmTcYHW+gqt9SlPcVv0NBcNbWdj6SAA37emkK0OH8tvwHEVtVGLV/avomAZLV7huYiEuUg2F7t4cvII381v4+axLF/IGanIM1JF8lIxZMOwLYjy44QNycdzGzisq9yUWU3+VxF/OfkQKwd38qPh7Xw2t4k/bYqej1gRRwbTfCCfJek1dWaLcSYtwf35bXwjt4Wbx7LsnDjMx3MbANg3Njs4WE5Evebgajj8bAdd7RV+pkZotXyuL2zk9hHj4L1ycCevmXyIZelFLNExzti1j2top/Nf9/H/cvfm4XJVZb7/Z6091HiGqlNnqEpCEkjISCAhEAiZyrFpp+bRtuHyQ0VFbQdar48PNFflol4faa9K24LaKo3N9WI7/GhxoB3PyUACJCRkJBMhgaTqjFVnqnHvvdbvj1WpkxMNBpu+v9u8z8NDDTt19t61a+213vf9fr7tgWLp8d0EnmBoJE5e19gxfITrH6rx8/5ddP/yKP+af6oJrHEbQKfPprOsGX6Cp8OCdw2bmf6zss4zehKF5ohfZFTX+F7ucZaf2snn8n38W//TnJoYMeAooZswptGgguhI8/P+XcycNdq8aJxwwLIXnmahX6V/X5z6wUG0FzDz8SOUSi77nBDrC9vwC3UG8diRvhxs2eSOHBpvRyTaEC4ULBiqRbhhpA+tNIOHY+ydfak5KmXO5c2Z1eTLMW7r70UA1XGHolB8bKCXA24IPWFms/+Ye4xTjs3zusySY3uYqLksv6qfyqTLZtXKvAMH+NhALz/IP0llzOHR/l1ElGbb0EEmTzkECN5Y3Mx9DdOGh/JPkLOMUOaNxc3Uyzb3FJ4k5wjcDmiXLu22kR5Xyw5fzW1m6fHdDB2KMWnBiGXxYGoDrxo4ybHxNo4SJXHfTt4/2MtzRDhVGmbz4AEWBy63Ztby4/x27ht8nF3DzzYNHE6Hr4Mm7GpnZgVRYaMxNk3lEZtK1SGpTI9yUWr6bckeN2BSKJaf2smvEtfwaP8uupRk+Slzvb+luAmtYa+s8m/9T/OJfnNNh9t9rhrczj5vhHUjj3O03IqjYb/t8eP8drbV+1mQmMmd+T4+me/lWSvMfbktfCSzltv7e9k+7lQqMgAAIABJREFUdJjP5PsYKLRQloKnZZST/hg/rR7ne7nHqaO4adj8biYk/Fv/0/wwv51RS/LXg70ojHN83bd4tH8XP0iuP9/h5I/Gy5hj3g7MF0LMFUK4wPXAI2duIIRYDnwTMyif1x34/wrlH5hiw6GLl5KbLPDtzizjqoYa9/hoZh2xVJ1IKqBbhJlXD7ikpmm941HUxDAHLrqEdclB1nYt5q60gQCt6lxAb/JqyjWHOYHFp/Km0CYzXU0Z7zJiXBqEWfzsXn6SWMfe2ZcCJvf4u+RqPpfOsrAuyRa28bXuLJY0Qo3WWLXZD3x9ehVf78rywcyaRo7POH58Np1l14wV2LYiUGZJeeHcArateIPsxhKah5PruLcrS1zBnlmX8ZPEOma4CT6T7+PZpYt4QfoMvWk+7drjwEWXYIcU6cwYD+Wf4M3py3mTSvC+zDUMvmEe78tcww/yT/KzxFrCrs8dmQ3U0DzZvZLLqkaYAbAkcHlN0ELW6qLbirOkwVve1nkld2Q2sDJlMlQfzazDtQK+3pVlS2oVO4ePokfy9CavpjgYw0XykcxaRoZiPJZaxTAu3QsncS+ZAba5pJIdZV4TH2ZTx1VY7Q7zdYiaZ6NLNQIleCCVZUHrKLo4hp0KMccLSDomtSKkoGthiTNhYloJ3lh16AqXeUfmam7r7yXS7uFgRDpX6kmCsRpLkrO5K72BJarcBNiHrYCnH++mvafMtS1D7JtzKZ9PNxw22uus6VrEScf0EHtVi5jw+V1yNbc2XDbu6c4yz5OoYpnHUqtwwgF3JFYxv+ajqppMg8kRjnq0JKfayjpml/jwQC/tgSIRBGRbLuYtxU1coKqMfvhyHk2s4abhPl7dYZqXxqVxgn84uY6qX+fN6cuRlm6aNgA8N9bP63ou5Qs9WVrbqxysDRJVhvAWige0tVWwMbWGu/J9zPJ8rqhJ5vtmXpuKVFjftYRTMmDXjBXNFZMKJItUmBWpeXyzK8uNmasoDblsSa3iEqeDx7uuYF50nErDM/J9mWtY4HbQ6bTw2ca5nOF7fDad5TUNxc8VnWZGnukewwIuZ5Jdw89yZdjM+B/IbeOhjg30Jq8moWBJcjZvTl9OTGnu78yScqp8Np0lHjUpnrcXNnLPWavMPzVerq6MhsXehzHI42eAH2it9wshPiOEeHNjsy8CceCHDeHdI+f4uGb8XzMwf6szy4LD+3ht9zI0MBZUEGFJWllIF2RUGOqZ1pSkZPzz1yKi7UhhZimbBw9wkAqWhkMTJ8kWtjHmhfCESRk8mljDiW+aroePZNaSFz7+GT98IcxS/YgDnpYMi6CZN1MYHvNt/b2Ewj79juTt6SvpFC5/PWjocmOYpfL2npW42vjGWbZisu4Y49EJB60FFlD0jew3oqEmQEiNheYG1WH2RWryuopW2nCdqw52RKN8ya2ZtQaaA4xrH1WGF1SZ92WuYUxa2G7A53N97NJjFOthAmF8Bee3z8ATULRgWPhYCL6U28RvEqsJOT41FJ12nL9IX849uU2M1MNMSsOKBsANky1sQ2tYHLjs8QtEwh6OFeAJQfevj0LD9PXQxUuplMzxOlLR8b1nqKI5RsQo/4TJY0pLgeMYE1cNNd8AmUQsRPcvj7L0+G7iKqA8aONVJW8tbKSlpUYnDl/qySIdTRXFpDT/VoQt9hdOMCYU44HLVbqFAxddgqckF88Zpl62qFadxueaw9JaEBIOV/tlBmyD9DxshXFl0MyhT0jDbJGJKJOBg5CaFmWKhO/d28r/mthHqeQipKZWcvhAZg3PLl2EdOF7HRuauMqH8k+wM7PCpOocm1FpszOzgnFVY03XouYg8JOwxycy63nBG0VaqumPdzpqyuf2/l4qJYcL3CRlKenWNlZINymEO9KX88n0BgIhuGGkj7gydRKAcVXFR7P81E7W+REeTazBCftIIGXHmJSwvzaIHQqoBhZ5VcG1A+qe1TRNPeSPkiHElsFn+FS+l09k1hMWAaeExyMRQ//bPnTYnOOGJFsKzXXplXhobslcw51n+Pc9Zyv2F05woYgxagkqwtxcPpWfYnb8OLmejw6c20zipcTLqfzTWv9Ca32x1voirfX/aLz2aa31I43Hr9Fad58hvHvzi3/ieQ7Mf0iWfcZ7HxdCaCFE6qzXrxBC+EKIt/2xz785s5q40k2vuFuGevlbZhOM+yQDqAzbqKo5QYtnDRFRCkIuulSgbUaV1lSFj2bWMagqRJRitFri8a4rWPWOOq0BzPIUly7txw0FaAUpbfGqquEIj/zVQspSsnsiwQLZQjoQPB62adWStsD8VDp9zZrhJ/h8OkutaqTKKTHVxrSYGBMNgNLuoKW51A58yc/CDlGliSVrHBg2aY4/L24mqhVfCo4R0uD7FldtGKDL9/lxcj22awhq0pUECJaf2kn+cCuRRJ1ZymY+EcoSWoWNcOHWWgwHiRIGoTpy4yIuka3ELY8ZVGkNNOWgSkjDh99eIqMdKo39dYQpyswKLN5Tb0Ug+HpXloRTaw4Ua7sWc+f7NvNYahWuG7BRTvBe1dnkZEdVwKGLl57+3hkuxIi2mFlOoAU3Za5iRARcEjb5xblvDOjyAyxL03bXb9FKM2JbCKFZ1j6Cn59sQqRiwid+gXGf/nw6S2nSpVNZzKkbFOiswGKGB78NhdDVgDVdi/hybhM9kRKDMmDxs3uJh+ok3pDGq9okuk1u/tbGD1wIzQVWnDXDTxBXkJozSVSZ79sN+fwouR4fTZev0OU6n3eKKF9SF/Da6w346tTECJGwxzeHu3EjPm1YTIyGOfhUJ1GtaFMBx1ybmzOrcd2AbZ1X0v6VJxCYNk2AdXY3rQ2ORlUr2rTEFTYtHTUiWjR9GL/elWXj4H4AEukyj/bvYsQ2JEC/Ipj/zAFCCo7UW5jvCaJa8aPkevpt6HWiuG5AyooxQ9ls6F7KNrtKSCi+N5SmPYBOGSGs4BZrNvWyjRRgCcHRaguTnkuHb7wXu6woKSV5U88KHkhl+WJuIwGCbzTSiKfBX/svXEatauMDXmBxYy3GXB2iWzvcle/jhpE+soVtdCrJV7qzHFITxJVGC/hQZi23ZtbieRZf7c6SpP6ySbL/07MyGvEAvy/LRggxC1P8e/6s1y3gbuBX5/Phn0pNL1g8mNrQfHzLWXZLe1/omvY8vXFK+bfEml6Y2f+9qSnxkf2dpN85ZaXznDv90BeHp8SM16pJbl09Rdsat6YXKM4m3p0Z7z1rf69XU0W6ZZnp9lB3Mqf5eGtfN28uThVNxsX0wlbXnKn921Crc/Nrp/o5z7Zf+vvfdTcf9+vp9LZ/+v4UHe2T6Q2sP6PQ+qPQdHVX8oxduOvrV3OPM7Wwe9qdvshbcHjqnn3N8BPT9+fV0+2Ojvxkijg2dse6ae8dK0zR5Y4sWsxz1pR12IVnFV2DM1y7/ktsGGf+1HGPVacf94sV/w5506+/Be4UafAee3pK8At66vw99VCYr8+Z2vbd8ekNSIvXThV+bx3onXadj358etH1p9XjzcdJMd1uqXxGX+9fD/Y2uRkAf5m+YvqxNG6QAGMWvP6Ma2NNbfr3e88Z5Ld3zpher/qdNTnt+cXRqe/wQ4PTr/HTNQyAD2TWcG116nP/pTK9IPvz8FRh9dNnOV5/7KzZ8F+dYfH1bf84L2e8jDnm/5A4r4H5D8myG/EVjMXU2Xv/EeDHwHklui/cc5DfhOqMFSL8emAPNw338YwLp8e00eEo/oQZDT0heCYkQCmEdNgz6zJ+dzLDPblN7A/GmlX8qwa30xKpcctQL28rbGSHG8Y/eorqhMOd+T5u6+/ljnwvHf9ykP0uDJUjPOYN8NeDvVw5sIPUjw+zNazZmVlBf2NmeEe+l0tO7KYmaBYY78hsYKce5wf5JwGY+OVdgBmcpGWcn4+6kpmPH6Ey6XJYmtHk9cUt7AzDIccUZU4Pym8tbOSCHYeJIEk9fJi8bTpLZjx2lOcPJ9kuSryqsJXkgwf4x9xj5PaZPPExNclNw32MVkIcpoIGasri7YWNbAx5nJoY4daBXn7BCN+tHOan/TubmEVfST460Mv380+QERH+erCXim9zy1Avry9uYfPgAXBcfpjfTiReJy7sZtfKlQM7KDTQom2f30TifiPx3pPrxKtbFAIXb7BOv65y2cldaKXpr0coS8kj46ZLpn7SMy2QWvBIRNH5kyP0H2lhZCTGu4d68UbN+b9+pI+nvTbuK+/nrYWN+FWLZ6w67xzuZftoCu/IAM9VzCWXLWzDa1yWuUqM1xe3EO+scuRYBwcuuqR57Q2cbGXr0EHAoDmtMByvNVx0RlNsGXyGYRHwi7CH9gJOqCjDwzE+NtDLIxGTt/3L9BUMTcQ4MdTGs88nuTu3kctO7qLwTIicbbEvZPO5dJYL9xzk0Hg7+4ihhie4vtGFs3FwP3sLx/GAxckLuC+3hU/me3li6BD9z7fymXwf38pN+WD+YnQ/78hczczHj+ChGGnkputli/7hFk7YmhtG+hiTxgHGFwLZOCenxlr49cAebuvv5bKTu3ggt41XFbZSK9l8NXiO7+UeZ7/tcbg2hLQ0VW2xq3SSy07uYpcbYr8LndE2fpjfzm39vU3SIEBZW5xSZXrDqrkieUqPMTQRY9DS/NQ1FnBfG32Kz+X7eFIbtvnG5NV8vIEZPVkv8s9WgQ8P9PKMFSGvq1TrNntGniNb2MagfHnoFS+nJPs/Iv49kuy3AKe01rvPen0GcB3w9ZfyeRfpECtyO7m20ZKVUAK/UUQ4VmmhMmruwm8rbDQdCNUa2qtQLBnBwA3pVRSC0rS88cnJFt6TWc0nMuv5eH8vsiXMxKSZgZ2edTx36UJ+6/dTEhZPDB2atk8emnLdDOQAb08bju8Re2oqqdBMNJpuC+9cwnfe0dd8rzQRYrwSMpLpGSuwbaMK+24qyxd6snwht5Fq44s/bdN+Og7rEicuX8AtQ738MrGGU9fMoyVWIyZsrkuv5KONYuPyUztZnrqIcIMp7ErFjsoLPOYPkhcu78ms5h8bP+pbM2sZVzWOjE6fHZUCkxcFo8YC2O+cZXLbcMkeL0bINXjF4xNmm9PAnPz6eU1cZ4s2su5Ou4Y/Icj7E/Qmr0aXanRYdXwBMz1NkC9QKdo8Y/mUtN3c1/bOMrqxhB/NRSgVQnwksxZHa2aHTdasOuGwvW5YFWOWwC8oTk2McH3DAWRzPdf4jsz5HTzeSsQKmnyQ69IrCTe6bU4vkcuDdtPBps813+ugrjKuPZLf3c/1I31IoVmZms8MZePXJD/Mb2drKEQiVGvanAGEWzwGLc3t/b10Nl5+a2Ejjobkd/dzdhSl4srwjOZvAKDmTzWjnS6mDZfHKWmf7T0rmVAebQ1fwLGRKOsL2ygIn0cSa9nOOFUJSeU1+cr9lsOrui/hpsxVfL0ry4KEEaFpJVgZzrCheyk2glJQw69LRiyLE+MDPJxcR1hBXAuybcaB9q2N2fr6LlO8HLFsftq/s3kNLUzMokOGKeDQFQgW1Y2D/UjFrDL+rf9pPpRZyzAuqzsXArC3cJzhoMRHMms5YRtF49VDZtJzf6dJmbwc8YoE5QshosAdTGdknI57gNu0fhF7XqY3bf+31o7mfWksqPBAKktRGtzjRzPruHrJKdyoWYp+uzPLxGlQt5BkusdYZo/zUP4JZtptzUECjO/bQhXisprg4eQ6nvuxoj1hBpV4o/ty7u6D3CjTJPH4XDrLvV1ZfpYw1ks92ibVXuKOzAae7F7JXBFhR/pyUo3+3renr6QnkPQNmGW8bAnz0QFTCNmSWoUfSP7RlczVIeKtVTzP4vbMeroCj1QAd/dkuTAws82LPMn3OjbwhZ4szy5dxMP5HYRTAT9IrifhVqlP2ghpihEnvFFateS69EpOrZ7PQifFTBHhR8n1WFLxeDbOlsFnaFMBa+sh7u7JkojEmaFsnhg6xCXJOc1z9IPkeiwU38ht4erGj+PGzFUsD8p8Lp2dalFqFPa0hsWNlJGnJL9Lmo6Bp2cuJ3SBS3SuuaS6W0vsm3MpI36I0AzJDLuFiO2DFFx8TYGbhvtYFBlDtkaJz/JZ6ttYmA6SkRsWIiRcPfQk38o9RijiE27x+IfcZlKBz5V2iq90Z5GW4jWuGVhm1QN6ek1aKyIsvpvKstbNcOCiS+i0a/ztOxQtbVVCDc7G59JZ0iKMGwr4TWI1s+vm+KJdPkdDFr9JrObddTOaLiLGcuKM3GDOT2tLlRVuF+0K3p0zhbk3yDHCIY9Eq2nZ2zv7UoTQZALBg6kNdPnms3ZmVpAKfIofWM7n0ll+nFzP2q7F3JZZT1xLqg3M6pt6VvDW9BW0x6u8r5FfPl1Mm93ajYfCthRzrDgXeJpXdV9CW0eZg/OWUiYgadW5ilYSAZy03SZDZh5l0laM2TrM5WKCQ8WTfDeVxfMs/im3lb6BfTgIjo3lCZQk2vArvK6wiQ8N9hLS0CmM8i8sLF7dvYy5tlm1STTXp1c18+EHiy/wz7ltzIuO42jjX9lmR5sD+rU9y1nmm3a/N1tpVncu5Lr0Sq63L8BBUMa0SO6aYSTfL+Yi/1LjlQrKvwiYC+wWQhzHNFXvFEL0YJQt32+8/jbgPiHEX5z9AWc2bf9l6wV/4m7AaPHcYoWz48L/59wkq7PjxQQTw2flf18s3ls7/6/2xhcRmJwdH33NubNEqYcPn/fnfNz7/ZnbueKyjgvPe9sXi92bzi30OTseSJ1/saf4wRXnfG/jN8/7Y14SHe2BWedPrduZOff+ne2U8mJxYvzl4UW8lPhlYs15b3t2F8mLxfsHzz3Yrq6+SDHn3xmvlOLftNBa79Vad2mt52it52D04Su01v1a67lnvP4j4INa63PCjMA4L8cUHF6whFYrzLuGe7mgkZO4J7eJ2riN26a4M72B9kBxoS/BscGyiYQ9LKm5ovNiumQY1ehd/U1iNW8pbsLWRpl0XWETbXc/hu0qrk+vagoyht4yn6iCiOOxTY8S0uCiELbA1bDw6D46A4HrBDhaIIXmntwmVncuZK6IYGPa7O7IbKD9a0/xu+RqvpjbiNIC1w7QWpDxIfAMOD+kBdcWtxjOtAZfwO+Sq5tFztv7exkrRLi2ZzlB2Zix2pbCjftEW+oIBOWghgjZtAgHGlCaf8htZlKaVjQwVjyt0rjBSKBYmWRABtyV3sBrwxcYmTUYl4lG3u70z2CFijAeONiapvs0WlFVDapZI3XTGqkZ52VhuMeyqxXhSg5dvBTHCfB9SYvwEbbAwoDnRcghZvvc35mlVHURrmFt2xpa7TqWBu1r3HjAwXlLqUmIJDyE0Hy123SLjBPgYAxuT7cpxvAREZfFyQuY1B5dgcdxXSYU8Sn5NjZGpKK1YNeMFXho7sttwbIVb5jYjoNmeeoitDKdIDHbx5KK13YvI6EE0UZT668S12C7iigWrYHGcs35tqRqSpjfkbkaxwlw25TpRhCComURi9epeTYppwpKMa+umWGXTQ4fGBVBE1D00/6dWAgi8TqLg+kD3bU9y3kk/xRuyOf5YJIBW3CBFcd2FdWqwzovjNW4DlK+37Q7O31jOFAfokMZs+Kvd2WJK0UkXueOzAau7VlOq24YATsBttZ8MLOGsAh4vOsKKo3r6dnaSBP8f9qwNKI0HcLlU/lePtQw/AWIt9ZoVcb04YmhQ828bYDia91ZHK2pCc3WoYNNU9Yv5zbRpgMiSEo1p5l6PPNz/z3xihiYzyHLftlCCBiyNOWSy7Bf4t6u7LTuBmlrVB3uyvcxYBtrJywL6hXqdYtACeba7XwntxW3kcoIGodWE8al+GeJtYx9YjWVSYfv502r0q2ZtXT+5AgVAVXf5mrRzqSEEenw357qoiAVhxcsoSg1WgsKwlzg93Zl2Tp0kLHGJfbz/l18PtdH4ealvKqwlVsza/G1pO5bpNpLxkTUUXgNa6nTXmtFqQ31TAbT5NmuGzAaVJCuSccIYeyVAk9S0QEazf0/66CuFX7V4k09K7g+vYqwNoP4BzJr+E5uK6PKIRA0jW5F43wU8OiQUzlkpzEwbx06yPLURZyQpqf19v5eJi3B63ouBaX4GrMo1x1GdJUFiZn4gRlsjzmaGVuPGPHIqMdwIYbvW/iBxNMCXVfMEWGOqyi65lHybaSGiOuhKzX8QQ8loBLYvHeoF11X1CctimNRJiX4FcMaKUpNxbcRGM5J4Mlmjr4gHGr7hlkU6qZVOJSERbtwuWjfM7ymuJWlFw0QeBKtTV7+rnwf78msRgWCmu9xXWETa9wMqm4IbEU/RM23yXljjEpNv6XQvjJO0GNhPDQK0Are1LOCum/h+5JqxSGKxcKj+0AZRSOYZfiCw/uwLcXzfhThmiX8gBdhXnuG1lCUTmVNE5Mc9QpUyw7brQoXtqX5s57L6Ikn2DZ6mJszq6lVbcLCJqagphVe1SIc9jjqaOqBhQIGbJu8bdrVRqthw2URDttkiUBJfiiGkWhGh6Oml1z7hLRgSXI2nmfMWAd0jQltM+yFaVUQRrK3cJwWLHwd8GADGiWACXw+m87ShsUlyTncmllLpeQwYgmqSFak5jWFP7/q301LAALN86LOitQ82kUIVxtT5rKQpLWD0oKqbqT19NkC8D8tAq3O+7//P+J8uzJ+T5Z91vtzzkGQe5fW+kfn8zciWnDZyV1YwljTfKEn25TdCKHxK5KbM6vp9g3ghGoNLPOlaS2aXRFnLn5+mVhDXMOYhElpcfLHk9i24oONQteFgc2JyxcQ0saUNEATU8YKyEZwd24jnmfhND7VRyMEVBtn7Ru5LdOMWkXIYVvnlcSx8Buz6+J4hDZlZsx+IKkJTclzeDC1AQFMCo3SgrbGsd7TnaVas9k2dJCgIqhJQaAE9bK5IDMixAw3QU5OpVNsIQlQXD/ShxDmS31H5mocNCE9lSfr0BYhDd24tAszu9zUcRXVwOLWxkxk1/CzFPEQjX/VXGpqhULQFqsSwuJQ8SSWNO4nS06na+o+SDPg+r5syolVWREAs0SFBuOKdw334jgBWBbCNTJ7pY1A53SEHJ8uX1Mv2yhfcGe+D0uY7waMEGe0MXsPhED7sLtyyvR0M3VxP9pYhktb4QXmPH46vYHv5LYipKYz2sb9ndnmtbPXijRQoYKBapGq0Mz2JcKVhAmIxWtojDfdzc9F8FBUPRvLUoQjHi1Y7JtzKUFN8Km8kRbf35lldedCAiVQQqCrHuOWQAk4OpojEzXiotO2YLdkriEsbGpVIyY6NpYnJhxC0uW/JJdjI1iR28mErjMpIdFosVNakKNGgFmFJgJFi9LYgK8FvpJYQtIibBSwVnZQE5JotM5RKhT8EmWhKQc1tBI4GE9DBVhoagK2ByOsTM0nT51xVW0WxccsSV0rdjJBSEPcCiMRBIGkIM35GvfLdAszKXhPZjURpWgRPjO1i9KKduHgi6lV7vOiTtj2iQqLUMMP8OWIV4K11H94JLpKhBvHP9duZ7lXpSY0Mir5Uk8WK6QIdyrasKkJYTz/WuMIO0R7okIiWeaDmTX8Wc9lhBp3uNcXt7Dq3T4hBQ4QaSzXQnGfFixCSOMbN1PREQR8tTvLnfk+koHibYWNzXY4xwlIBWDbAYsCl1jcCC/+In05H8ms5f2DvazqXMD16VUkvrGLQT/M53N9RC0fIeBht6Hya/Noba1yoW9k3jcN9/G/K0foUoKo69EaKB5JrCWuoHvWBB/MrMHtgJuG+4jHahx8oRM7FPDl3CZ+N7CXTmWxp5ZHK2gRDrOEyZ8LoflsdoQLdIgWy9iEdgXwup5L6QjgznwfkyhiWBwoPM+6kcfpbC03ZyLvyFzNLMK0uzVe272Mh5PryNfHIBTldcXHsGxFvDEIOE5A2PFx0BxbthDZ2YqdjhOL14m11FBK4AiNkzb7ZkuFiLpc9hrT72vZCjmzG2dGjCurPlLAFf07kFELJxqQ6CzTGihaZtSRtubrXVlcKyCMuS7skGKpMCTBObKMk7J5VXQuKW0T1opWbPZfuIyZrRO0v/1iQvEAX0kOXHRJ09TTdhVD5TEGLVMQrhQdPAERyycRqXJRLE1PIIkoQBpmtNaCVixcren3xnFPd8SEAmxb8cXcRpYe382pZ9t4MLWB1kCR8n22Dh3EkpqZooKIusz3a0S1YmVqPovC3dQa6Ycb0quYrV0q2iMarTd0nrBp7DAazf8u7GK2dnl65nISMmxu8AREEh6/nEzRjcswDh8b6KVL1LC1psvXpFsnsYTGERbduGQL22jVgjbl44QDVqkoT48cIx0I5ke6aU1VcEWA1hpPSFosj7iCNTJFwooQxSJpxVilY9yV3sACXWYZUYaCEhaCU7UCFmBZiqU1TVQEfMpeQBTJTZmrCGNRbEj4T4o6T48cQyJIBIYeeEdmAxYC21KUdUAYRUK9PHnnV0Qf8//pOGyF//hGjaiWnXO+d/DB6UW6jreem0+9wZ1Obxt60/xzbPnSTtr74uemff1NaDrd60yBydmx8qrpVlfv//NzU+s6vndu4t7Z8WLEuPf408UBCxOzzrGl6UU/3zi+JX7e276leG7K32nl4eno+Jdz78PET85//1b453bJeCw1HbX7m8vPjTSftXB02vP9F57b2sx/CUvmK9vPXZi+tmW6iCnQ5x7IdqQvP++/maJ+zvdO9yCfjnfrnnNue7+cXrS2XmTce5N3boLivzdeETnm/+iwHM3suuLkVfPJiBAX+B7LagqrO27cd7skdsplhrLoVB4RpRGOA5ZNOOrhRALuy21hhWxvervtSF+OawckA0XC12RCZUQ0ghMNuDu3kRmBZJ7n0fmTI8R0QCRuLjzZ+CI+85S5uGKpGu2BJhz1+NiAMUqdVwsQCBLa4oFUlmVOitkizNhdr6HLrnJPtyG7tbRVGRsLMzeoEmoNCLeYwsbTM81gOKseGPY1WS5+AAAgAElEQVSs69OiA97Us4Ie38cKKVqxkHHLyKCjPjJuEWoNuC2znjsyG3jkkRTLwxnCyYB/zm1rgvpbkxXuyGxggQdtsSqzPZ+o0vyqfzfxhvuxBWysn+LO9AYsIQlHPTxhGCILtZnxx+M1Asxy8spwBhyXg8UXaO2scqWKckvmGtp7yiQ7S7TTUGg5DsKWxFM1QjGflrYqUdcDWxLXgkR7BdHRTjRaZ2PyaqKtdXS50si3CpJRMyB2PHQQ6ZpWxt8kVmO1WzhtRhYdi9S5IDBM5lCHItOAN8QbSM0oFgkt6LCMfL09XcbzLJ450IUV0XQmJtk+luL+zix3pTcQm2nqBitrNaJa0LZI0d0xSdj1Kdccnhg6hKshFfjIiENrrEpLd5V5nmF3WK2SjIgQKHPc0USdu9IbOLZsIVYcugOPNm3409+pttPRNWlWDpEQnpbMaJvgareHg9UBEkpwe2Y9ncLlk/le4jKEEw74p9xWbspcxVB5jOfHB1koW9FA5wWT/FnQwtJ6jTQu0jYrs7UVxcqZAw2+sqBFB8Zd3la0tlTJyhTLaobPnPE07XadWLfHLM+k+Wxt8r+Wq0lEq8yRMebMLRCyjZR+ti9YZLVxTE2yykpyb1eWWb6gNVY1tQOluaiuWRDpQSJoSVZx0ERtj5QVJaEtYtjcm9tMRxDQ2VrmKs+sLGdqh7I0Yp94tMY3cltoaasyU4R5fXHL7yFG/9T4Tz9j/kOcDCHEfxdCnGqQkp4WQvx54/Urz3httxDiuvPZiVlPHqZoS4r5KAPUOe449NsW/gumEX3siEXt+TrPSo/XFR/jhCvQkyW0X2N8NExxIMp16ZXkqDESuMxu7WZl/ilqnm0UYkJwRf8OVP8Q1TEzwzluBTwSEeTWzqMgHQaHzJJ4TFr8LLG2mW+sjjn024LJ8TDvylxNcSRKbwQezu/gM/k+3jXcy7dyj3FUl9FDZtb9rOWzM7OC0WKEtrYqJ2SYiX6XsaEIgYBS1eW7qSzHXIuTjqQwEeWI67CzdII3FjdTPBVlnIBg3GdQhRgvRCgdM7D4MorP5/p4obFQqI9J/jJ9BR/MrOHh5DoKQzHy1NnuBhQnIxx2bU44glktKXKO4D2Z1ZQIWOikOEyFR/JPcSyfoIpx5r6jAaQZHo1xzBU81LGBIV2DipHoDj7fQq8c57A/avzlXkix1wmTWzsPNTxGMFJixtYjjA9HUIEptgXFKnEtKI5GUKeGqFYc1he2MToURY9O4A9M8pxjM1yKsHf2pYzcuIigoR4eki7jhwSVQYvnHUm15jAmNbcO9FIbkTwqzKw0N95Cbu08vj++l92yykhgVJZj/REqdYcqFqUBh/GJMF2BxykbfhMMMvmCuR5eU9xKFU29P2CoEKO/HKWmzDBQsOCoaxMUqwyMx5gcDPGMY1ZjtX5FgGYIl5EXYpSLxiX6wj0H8YqCI45LFcn9nVm+nNvE8ECcim+jxsoMS5vJssu/TpgVTrFhHfbV3Gbu7skSkQ5+3eI9mdVNuymA53WZURFQzEX5rs6Tt1wmCKgUbKoTDr+KwLeHeygLOGKH8BAcDFksfnYvpZLLb9UQm0MBy0/t5IaRPk4FEcZPhjjhSh4tHWXIhhWpeYwNhHm+FOe4KnHieIJy3eG4Y/G4U+Oruc0ski08OLGPzVaZQQueKiUpSsWOkOIZF349sIcJAoqDMQ67FpOeQ1X79Aufb+S28IHMGoqWxdLjuzlpmwHwqKhiadNnnh+P84nMekaLUZ70h/hWZ5byy9RB90qYMT/AH+BkAF85g5b0i8Zr+zCmg5c1/s03hRB/1L7qyKLFRJWZlY6rOhVhmAAybn4YobiPk5J8I7eFh5PraDW2AgjbqAUdN+Dh/A4u0mGqQrI0mmHPrMuaxSdbG8xm7l9LuFEz65yhLJZ7NpnNR7G1pr21wr1dWV5woN2qNz3InLBpzRJC80BuG62tVeYEFrdkruGmzFXc25VttvK0f+0pqoHFYt+YbyY6ytRrFmGtccIB0tK0BaacMEvVEJjCXKq9RFug+ZJ7CXemN9CSrHJfbgvBJLThI4XGDimUL5ipzOns9sFC4LYofpjfTlo7SA22pUhhmMBSaLp9TbuC7lCCuIIVfoiLVYi0CNHWyBUnw1WS2uLqzoXckF5FqFFQ9dAklc+3lo6B7fJIYi0rcjuZLaJsHNyPV7dIhqp0+ho3JZFtUUTY5tiyhQipmZgIIaVGSMFkI38qE3FCYZ+HOjbQkSkhU+0IKej2FW2hOvsnEwjXwm60p4e1Itrh40RMI2Q0OrWklo5itow1Cqkap13QP1lkJiGSVp0ObBY/uxfHCmi36oTbPFw7IOHUSCjYPHiASMJvetZ9Lt/HaC7CCzpCi+URtT3enr6SCzzzQxGuJGwFqECwoib5QXI9tz+XIq0dliZHaElWCbd4lIVm14wVuB0QU6AEdPkGxxqP18gWtiFCDmGtce2Ai6I9XBzuIqwFH8is4dPpDRSkYrFso1J2mm1pp+FFokEGDEU8Zttt2BoiSMLtPkJoOrTFXM8UHuf7NaxGEXjXjBVcObCDZVaC+YHN411XcH16FW8rbERaprC3MjqLTh/SdgtuKKDLqdIhQ8RDdSKOWTWmtcs7MlcTRjIrnOL7+Se4vb+XRBAQ1gIHQZcynR0ztEPX7AmW1HzClmFJx5F8PLOOb+S2UBPwcHIdodMFXQSBMNe3I0y+Phzy6Lbi3DLUy7kTly8t/tN3ZbwIJ+MPbVtu8EkBwpyncOb9BYtxKajXbIQQrAymckufTm9AK4E/ak7Q5Rf2m4VztYb2a/Rn5xF45jAOUCYQgp/372JwMsrF7zTLo1HL9JFGW+vUyxZ35zbSqqYOviYEvy518KHBXnp8+JEb4nlt7IYu2HGYhK9xQ6YNSGtBVcC3co/xYO5x/mthC/+c28ZJ30BeDtph9tnmFPh1i697LVSFoFZy2DTZwYglCJTkVYWtPKwHcbUxX20LAqIqYK4nmCyGWJmajwybVjqlBfuf6UJruK3f9IhOShjXdfyK4PsdGxgUPodDFp5vcds1/XyuAcqfQRUfKKsawxbceEOJh7wT/KLyHArDbB6vhSiIgA/oNJPaoywUIdvnM/k+Xl/cQvevj3Lrhx4jjOLYsoUEGEVmNGYMZ591BamHD6P9gOQ/7ePEyQTjE2GDOZWajn85SE0YFgZSkNmg+e/qKMV8FD0+CdI04FhSsSReJPlP+/AmBEcXL6YmTOOssDTPWwHjE+Fml4zyJEO6xogl+GXEovOnR7guvZJjukI8XCempemOUJJlf9OGtGGiGuLvLcmHB3pZmJhFbdzc/H+QXM8HMmvoXFylYAnWNEBMN9TC9Ntm/2RLiHsdEBIeC/kEQvC8P8Fn8n0Ux6J8eaiT/hdamedLIpE6zz7RjhLGDHVP2Obvhx+nVnV4JLGWb/5LjJBWDFWi9A3s40rRRkloSvg8pQ2F757cJsJhrzlre3W3yVEf94pN/vfNVZuk8jmgJvArkosP7UcBi3SZ73VsYELblBrFyQd1nCe7V7InKFJrYDVXK3MH/MVIN3fke5nQHlGl+Xn/LixHUfFt+lWFFbmdXDmwg/s7s0QRjKgqOWpMqhqfyKw3fphojooq/dT58EAvNeXxRjnGyAsxxqRFoMwvroLiiC6xJDmb1sD0N7cF8M2uLD6KqDLFv2+HNbc1UAWXEec3idWcv/TnxeOV3JXxYSHEnkaqo+kHJIRYJYTYD+wFPnDGQH3OuK9l+sEfFFNqvtPV89PxqxMzpj3vP9Jyzs89cP90i6DE66fIdDvs6cWM9WdY3tyT28T/nDt1Lxqxp6+fus6oKX41OV0R9ar26cWXd/hTyrDX90wv4F0rp5PyvuhM0clWut3T3rv0yim11725zbzrDVPFv+vPUgx+cMsUZe8Za7rasf3vn5z2/H+eYd3099M8JWkC0AG++p3X8rriFEjnJ6Vzqwvnzp5+Hy+8c8m057m+M85ndPr+XXJiGnrFIF4bkXyRHtY3Vj3Gbp8SHxwtt057/7dfmSKrPZSfTr87E8QDsOiM7+y6wvTi498E02dQP7h0atsPx6cXkGfNn3p+R76XvQvnNJ+//8bpBcaHqs82H0fPWmQ+r6dvGzmDPvf/RqZfm2fS5W4c6SN2xlD22sq5Z39/1v7ivLEzwU/Pi+m/q7P5FYvUVPH+22fQ+M6ON4Xn8IIztf9nqwDfWZn6vvcwnXb3741XJCsDAyi6CLgMyANfOv2G1voJrfUS4Argb4UQf7DF4kxWxo/KJ5BAKOxT1T6BaEhxFXytO4vbppCucdZoDVQTRylCMS47uat5Jz7kTQ1sA9LFthQ/SK43AHDfh5CL5ZgTXSbgsKMYeovpvnAaOcNUYP7/t8dTTW1+a2BaoQRGUBBVugl/OX0xXe4YmfGukRT35jaza8YKSpMuYXcKyK+VoFUZ+6f7O7N0BQYh+mT3SjwhmWu3GaVb3COtbex2m2pg4YZ8hATlm+N8Vfcl3Ptoii1jR5r9zf+Q20yXD62tVdqEw7AI2N6zkqjSJAJwhd08b3PdJEvCPfxj7jGKqkpnSwmBgaSHhcWXc5tw7YBZnukBfnX3MoRrgOpCQDs2EcuA4bUWLKuaH7+IhCl+YDnS0rTEakSjdUJhA/+JaGM8iuNQq9r8A7ObXRWyxaxspNR8qzNL4eal2BGNtBUjtjFKsMIYFadUjIiAT6c3YIUMt9oTpvug7QubiQub2SKMq03qY+nx3QihWXNNHuUJQrbPXekN3JnewMHiC0hLm/5iIQyQ6oSFKwN2pC+n7DtYUvK0KNPpa4RrEyhJuMUjox3aVICMGiVhLFzHdgNisTrhM8a/qNKkfJ+fJNbxkUFzE+qw6uD5eEI0+8UTdoyEEjyYexwLSVuDhRJu8RgMjJP2bweMl6MjTG99ZdIljOSY4xAXNlZIIYRmtm9m/J9Mb8ASmiFbkvEUFyTGcWxFWsboCIxzzmkKnBMOuDmzmmJQwdGaTDxJuN0n7nq0ixChiPmOQ0rzjdwWxlWNFmxC0jEF6XwvIYybS0ib2W+LHUFj4P0VKRBC82c9l9GhLZZhJlQzfE3YCpp6gC5c4+BsQxVJAZ9Q2GeljptWxT80mPwJ8YqcMWutB7TWQQNU9C3gyj+wzTPAJLD07Pca7zdZGZ/MTTAuYd6BA/yqfzdhBVGlEK5ZcvolgQxLJvBJNiSbSAHS4ujixbR1mNTHxU4HHQ3Z8IWyTN23OOFKZng+HVadtrt+i+Uo7shsYCYh5nmSzp8cIal8lh7fzfsy1zAuzUCXxOGBVJbnLl3Iu4Z7qdcsJoXC9y2uH+ljaTjdXE7emlnbREwu7xjm3q6syfWlS4xXQiQCRbyzirQ0ViMPfJpg1h6A6wSGOoYg7fk4kYA7833ouqI9XCNoDMiRRJ2bM6v53cBeEgHc0H4psW6/SZqLN2aX38o9RhSJEJqI0rxzuBdbTAkrVusWBgIzA/n1wB5836JLWVwoW0iLMF/rzrIit5NJyygPZ1kxdGWCVKjK5GiIy6uaditKvWbT2lIlLgIGXj8PpECXamgtiCequCHzYx798OVUhCbRWkGXKkipeV3xMZqTEaVp177pe9YgLIlwTQHt3UO9qDoEVbi05iGl5mLf4jP5PnQgOClqhDSkYhVG/mohY9r0bu8KW5SF5vCCJcSjdXZs6UZYppZQFIq7GisxJ6Y4UR3ihpE+WrBona8I2QHjtRDd7ZOsTi3kEqJMWkYU4toBdtjoSl0CVNU4gVTrBjLVni7Tbxulp5sSXD/SRxjFW4qbCNDEW6tcM/wEIhIiQNDu1nhr+gq2DR1EYLCfSeFwSvjMFBFqJYe1Vic90gzqr+5exhI7wd25jbQkqxQwx3uRiCJt00L4gq15JLGWOb5AI5jjmd/E+ESYaKyOFIIJCaGIz62ZtWzquAq/Lrk0CBEWNoOOJGqHmegPIYQmQDFeNIXZmhR8oSfLPLudLm2zfegwd+c28pXuLAGCqBa0B1ARMOlX2eOPkJxRpsv3CdvGOWdMKD6X7+OILhNVRmA1bMGG7qVMECA1zPA07dKjHRvfl/xUGYrg7We15v2p8YqcMQsh0mc8vQ5T9KNhSGg3Hs8GFgLH/9jnHbjoEtobswxLSoZt4++l68Znr14yg8p3cluZEDaeAF33oV6hPOFSLZml3Wn8JsB2GaMSWCQCowq7ZvgJYzNUMa1WHprBxopxTNo8PXM5h/xRTjVWiWP4vGu4l7m7D/KlniyTkyG+kNtIvW5xd0+WH+e3M9xoEythcJ6jH78KIYz7gudb1MsW/ytkUReC+qTN5GiI4cbfDBBMSqhIwwq5vzPL66sOby5upjrucEN6FaquOFWNEQQSVYeJgTCp03wCYRjM3oTguDZOzXUhCALByI2LCGmoejaT0ogxdgwfYa7nUxQB/TIgZUV5T2Y1W1Kr8HxJSWgeq55kXzDKhwd62d6zEgXYGG82Ap+ab+H7Ft8Pldk6dBAVCEoll0HhGl52rU7ywQPUyxbFwRiliRCBL1ETxj1lybE96EqdC159RhopCFATdQYsh7pvJMDaC1CNzMMvEmupj0kzCNvm2KU2kH+Ephu3af2lqgHDfokv5jZyVdUnogW+L1l6fDerP2RTKToMj8Zo07Jpa6Q8QZtjltutWuIXFE+qFnwtGBmLsnnwAGNCGVm7azNUizA5FGZEBARI3rvbpEwCJVG+pFJ0OSl9KpNuU7k6IhuqPDQTY2YBqSYqTQ7JcFDmtsx6agIOFJ7nvtwWCrrOgK7h1S0OUeI7ua3ckF7FpuEDfCP/GG9PX0ll0mFCewQCCvgEdaOGlAjSoQp52zCSry1uaf6tBYf38b2GhLo06XJYTTCqHCxHMSEhIh0sbdSI0tKcqMWJCZtjlRYKE1HePdTLuNQc8EaYFIoVKdNTXZJGWj0mFHtcc+PKlUe42u6iMuoQCEHVtxkMShxQ46zqXMAaFWdCSirKpiOAkqoTQlKSMGwL/i0UpkRAqRSi04rxSGItH89MN1b4U+M//Yz5HJyMvxNC7BVC7AGywMcam6/BEOeeBh7GAIzOrYR4GeJskcGLxcx3pf/4RucRncEf3+Z0fFCef5P82wsvD2v2pQhM1pzlNvJ/Ip795flT/v78RUQ3LyVKG0+e97YXet4f36gR31k+/sc3Oo94KXS5q1ILXpa/+VLiouj5H+ci7+XpNv58ru9l+Zw/FK+Erozf42RorW/SWl+itV6mtX6z1jrf2PZBrfWSRgvdij9GlTsdi5/diycMw/bVXZfQ4zVARJM+VaGxHEVQVnw0s47Z4Uk8gREl1EosPb6bUsnkKKPCZrxROLl1oJdR4TBmwSnHXCi6VqdesTkp6lgN6efgG+Zha81k1WWm3UJHYEwf/+6KoeasytFmRvTm9OUoLSg2rruqDgwdC8PxaP/S45waamVUQqAEWglKVdfMmCs2WgnGhKbi2fhi6uRX6g5DlgG3f7U7S71m8VD+Cfxxo3xTSlAtWDjhgADNjZmruOktpsCmleBf809xc2Y1ltaUSiFuz6znqKhSVxaO1jgaYm6YnWGbf8htJsBAb77T4DIESlISismgyke8BP81s45iLcStA70MNtxJ8Or8nePjB2avX929DM+zkKdBTB2gRiYYfMM8KpMuni9xQz5HJ9pIftd0CuxIX46ueQQNWa3nWeAHaKVRmG6VmhCocQ/liaYQR0iojhtHFT+QjFhGJFOftMlTpyqgqFycC5NUtc8tmWuYEBbPi/r/1955x8lRXfn+eyt1mp4cWwGBIpKQQCAkgsKAjcEB22uvbZYleJ0WY7BZHg+Wx5rnXa8X71vbLGvMmmCDsQ2LAzbGmGDTCighIQmUpUEo9uQ806nCfX/cmlFPMyN6QLKwmPP51Kerbp2ue09V3Vv3nvM752BaLsvLz2PF9vHoptI7f6NxGQEEd9QtJd1jMC2g7AN3Ni6jpaEIE4+w7hAyjxjObmyOI/uVO75a3qug89lOFW85FLBJJ02SvRYCFbPC7ZM8WFWPI+DpskXcHVExlJ8vuwDZn0GXkpRtDrp0h6SKkfGZugU81riOFi9JIGQTEQYfqzubxxrXMSlaQ4vdM5gYIYBOmatmydk+g3TSpE94vG6riOMmku/V1NNqiMGA82eUT+KQ7pLMmpSJAK4QZJMG/9QYp8nu4aChdMHppIkpPTLSoy9tEQlk+WF1PQEJ61p3YSM5mFTG7jsa43RoBmVS5UM8qHv0Z9MclGlS/SaHTR1XCsYZUSZpRWgIXtL6uLYtjkCSFSredJNM4wroyhmZdM2jRJg0mgalxyiIkZRewduJoHeF59/u6bMwpTKw7c+006ULpac1VIZnPeDh9Cm0xJZsiR+CUYJhsX3yGZh+RpGB9KEDuNRTrH4q/b71XNmF4HmYQYeHEqvZK5P0aVD9+wYEKoTlzxJr0aXKMlH12z2DfvmHdQ9d85gpitCEGug0IagUFl9pjvPfiZc45PbRfesF9EqD10UGTUj6+wJYhsq2LYSC3GWFMpiVuR79QqkkXCmYnPV4snEDHsr4d0XdEddfTwrMsMLPtpKlFou7f1fGYbsbz/d8+3FiNZuDypHmrsRyaglwUcdqijyV5qc/m0aiEt/u8noJiiOBi3oci+8kVlBtlXCb3Mt3EysI6woeKPDdtk2LpxpfIRzOEhQ6rU4vGdvA8wR7LUHV7/YgSsJU/74BK+AQtBxcR2N6WSftn55BsRQksyZ6dQlSqsQFwZANho7QBE0GZD1NJTrw38pwRKk8rDKPQJF6kBnH4LamOKX+s9lht3NbU5weXcPZ18nGtgZWpg7gARWoj+GSjjXUzzuE5wpSrs6ddUu5vTFOUngYAY9X+vbzaOVSrqhbQDBsowupIvH52UMEKm6DTLuYqInCQFQ7IyJZZfmJbS31HrbILLru4Tnq+Xbrgg93ruScA7txPY0eYaCVRrCFwJaCF3yjXo+m7AMtfk61HjdNJmVy0O2n0VE2gT1dh6kwo4TRMQz1oTlsCF53j8xoyz2NWUWd3N4Yp0/o1DkKo/xi+fmsqFjIlo59THAVfO2Q28vHO1ZgWB7fqa3ndKuKaldwINtBaW2SqHDolBmCpkN7OsSXWuK0C5eLa+bQgc2EsPqo/UtdPZWew8/TDVzfEqfa0wibAdI42LZOkb/K9FAR6Gaa5QSFzgNV9ZjCI+sbyA00HnT2EfFUUowGrxdPCg66/XypJY55jDQLJ4ODyXEn3fQocSVm0OH80ESKPUmV42HUhJmRBatcEKjWuDW2hEme+qISsBBGANNyCYVtro8t4kyiFEuHdh8HnbINylyHSkdSYmboX5kgWOJwR91SwkKn2IOOz86mSmQwLJcrYwuHPPiIB6/PPp05GUFpaYq7EsuJFGUpcyWX1MzF8R/a+VUzqNbDlHx7FWFcznIDBC2H4rIUwYBNxFOdORi1qXE1lnSsoVfTODXrkRJQUZJEoGZV420PzZAEhY6fGEKhG2o1IpVZqrAwEBRJweb2vQRK3cEYtafk5NWKuRqbxs0jpWncW13POZVTuchO8uPEamJaiAA6RehsO20OJWaGr9ct5VSjlHNCCm1SFMxS68A4N8PvmzZBMMz62nMoKsswXYbodVJU1/RSHE1T53/8tFLV4FCJTaQkQyZrUFKTRota9AlJRUkSdJ3ysiQf71hBqMhGhEPoNUWcmbGpLu2nxHXRSwJYFTBt1zaeLF+M0MAqU/c6GsyoyGsSQpUOS806flhdT5nrUvnkbqaWjmNxaCIrgx4hKZi2axtbJ81ly4ZqhIBYeS9XFqtZ3ncTKwgUuywsOhVTwoVuGN30eEMPoglJJGBzbew8alyNaleAIagOJzECHmE0qlyH67eX4SHJ2jpWyCFanqZaWJyx/1XMckHQg6lZm9+WLeZzVecSCNpY/izsyvZlg3GTAWL+fcxKZdCVSCpP7ec0PcpMs2LwXYtoCo1hBl2qhMVtTXFm6aVEYg6hoiwTbcn+nmIeqawnLF1CnketAxd1rEYTknmVUyjyoCSc5mpZwx/KLsQMuRR5CkoYkkrXbYQkRZbNLK2YaDRDrFh54k531CpqigwS9vXnlS6UWWkuDk3ittgSbmmKM614HGUiQGWsjx4dysJpSoXFeAK0ygyTZXCwvw3EJgoLnds5hRIPJjkZFooyiovTVGkhVlUuoGIUasSj0Unpku2X3yCE2CmE2CaE+He/7P1CiFd8/fMrQoiLCmlEf3eAXk2Q7AnwYt/reAieC9q4rSmuaF9GqlHg9Hi0YJMQAVp0kKk0WCFcW6O3N8C9iZWs8TrYErBY3bqTRyrrOeOvM6wN6WSEYI8XUbnj2iwaSFGKSUqAzLrsFSGe76vkZ4m1dOrweMVSQGXo1nTJLksNEgDd3UE2WR4pT+Ewvl63lDojSpP/MZhY3c1+3eVAXxTPFdye0enSBUKT9HcHyAp4rGIpASn5VMdymjSXTNqgU9fYaxl8smM52aRK8yMd+G3ZYvr7A2x8sQo3o+IPb3A76fOhR3hwUCa5OnYeff7TbP3oVG5qjnMwGaFdFyQ1aMx0EDcVPrwEgwa7g/VuBw2dpWRdhXLYnE7wP03ruTG2iMb+CFtMh358VUY6yet2EYkDJbxKH6cFq+lsD9PbFxycU7iNbbR9YhqZPoNkr4WuqTjNbneGBpGmvTuM19ZNzSUB7q2up7NVOZjYb3TToRns7CpjQrgfL+MgHXXVjNDoTxj0JwzuqamnIxWkFINGXZLp0mkiQ0KXFGtKL1xlRinDoBuHNuGyadw8WnvCzP+SjmZIkkmLrq6QCivr94B2L81n2pdxj72H7o4Q3ZpKm9WSDPNwYg03NcfJCBCa4AY7RW97kDlZnW5Np91Lsdvt5tzmDXS3h+huD5HCY2NsHrtWlXNNW5w9lkmXrrPN7aKvL6CCVRnaYK7MXeEAACAASURBVLqngVRL+3y35JdadnB3YgUCwaGdJRSj0+gl+UjtPFrtXl5s3kIrWXo7grTKLN+uracbh96DJj9sq2GbBcWazQorQ7dmsNfS6dRhTdW5XNi2jrZsDy+ZKjmuI1SW9f4ui1YfGdGuqw9ATyJAYybEK24HN/TobO0r497qejYbWYo1Fc/Dlgrl1KlDYzbMQS/J6zLJDbFFfrQ46GoO4wF9aYtFdlBB4NB4jV76NejAYouW5vK6s3kosZrDpqBbg5+GJP/cuIyeniANdgdNXnAwvvU7pZNhxvwweS7ZQoh64KPAXB+z/B/+qTbgI1LKM4BrgEffTqPcUfjDp1Ijp7F58YmhTgbjPzdydLn57lAjXcuHRo7gNckt/O34h2xgxHODg4NPP8g2jMg7Y/JQx5WvfbR7BE6o+u2eAlt39OhtpztDHR1uSG0akbepfuT7lU/bHh/ZS/+1TMmQ47QY+WXI9A29TvftI1vs733kLSMDDNJce+R0UTc5Q52CfjZ5ZN7TTm8fcvxfkZFleX/NyJHn8umyo0QE/FtzaES7wDHSkd6cGdmRK99Id5E7cvTA3xtDjYjXHyW11BWpYzQKD0Ou5xW8nQh6uy7Z1wF3SSkzPk+L/7tJSpnwebYBISHEyCPTQCN0yeumh5RwXmQSTQZMkkf+pgfUzflxYjVZIQhKEEURZLILXfPQNfVVe6H5Ncr8pc4ss4cJZj/fSizDkJIy10UmlQfV443raJNZij2FYAhKiStVpg5TQrHn8qWNpYOebykh2TppLrfGlmAaSv2wqm0nDyRWIYAuLzMI/q/73l/Rik1YuNhZnR6p0ia5tjKGRaSKHewICEgF0ZqX2MjnW+O0prt4oKoeIeCLsQuQWeUurmseZsTDTmuE0PhT82vc+ZR6+fuale73J4k13NwUZ2NsHp+Nnc/VsfMoEi6lruSWpjiHe9tJ+svmRplhglnCC82vcWbFaVi6y42xRezsPMj00vFUS4OA8GgwXLp0FUMDT8UtDloOv2hcz/5MG+Fwlt6sRaWrEqEK06DyV7uxbR0roB7Emqpz0YI602TId8n2k7U6KhUTmoZebmFJ5ZorATxJpl1j55TZXNsWJ1DsoJtKV25pHh3YBBFYYQeBIC0k7dLC3tVEpRGhDw9bevTiEAplsTSPOWmHdK+J7ej8SA8O4mHdlGBd5x4erKqnPjSJCWf3UmRm6fJMTB8O9rG6s0kLidOWpZIsRWVpDplgSYkekixr3sra6vmYlosmJL3SIRiyEZoKxmNKxTtr72uc27xBGf96U4zzjdy/alxPs9NLi3D4ez+u+NWx89jY1kBJaYrvJFbQkFaeeVnP4Q9Nm4j4cdY0Ibi1KU5augSLlTNGpSdY3L6WOmnRo+mEJdQ6Ci+8pupcKqwo5ZisrZ7PL4QCTbmOxh2NcQVZk9Bq9/pxYiRRYVERTDHZ6OP6ljjF6GxJJbg2dh7tdi83xFQc8ahwmKlF6dSVwxOoaH9CU3aZpGvwm8ZX6JUOOhoRYfJ02SJC0iOIzlONr/A5P4PLft0lKVTcZgBL6HyiY/mgLvqd0l88XG4EmgYsEkKsE0IsF0LMH4bnE8DGgcH7aGRaLsVSIxzNsrKvgWIPJtiAIQYz7mqWyvdV5jqMtz2wbYShBu+elPo9v2oG/hhNU/qIW/eV7csICxdMg0DEYVH1TCqFRdKXvltXL/JiUY4rjkC0LKmyQpdIjXTGoJks/RmTgFR464/XnUOxFJRrAT5edw7dt5zPa1c/TwANQ3gEIzY1Zmow07BuqhxwaVcn5Eluao4PQF15uLKeiBlCB5ysxla7HWFAiXQxTRfPVm/kgFW6WOo827SZcIUykH0hdgH3Vddj6B4acIYX5KKO1XQagm/46JLkYK41SSAngGLW1enHZUn1LD4SnKRCTppZvpNYwTVtcTqdfjDVykTXVOoqXai0Upbmog/o4TRB+xUzME0XM+hgGC6xiWpmH5bKwIrnETAdglJ9iEUoAJ6kSLqEdYdZRi9oAjPiITR4tHIpRpFyBAHo9wxmeAFMqcLFTpIBdAQlOAhDo1RYpHG5Km2pIOuWMtx6qMD8AFM9pRe9PbYUIyLpz6Ypdj3qpIGwBE3ZEEE8AprLxrYG3u8WU+GpDClJqePaGm/4AegHMnTpmiQQdLACjloCuxqapaCVAT8rzoyyCbxccw6GUF6EhpREA1lujC2iLdPNZM+kW9o827R5EK8+EG+8oStBm5vE0gwurzub+xOrCIZt309OBaVxsyr41D7dZeukuVR4AktKJtsZ2gyF5QeVpaba09GE5AuO0l2Ho1nuqFtKtR6hT0j2dB3GDLkEhIcldDxPcG7zBgB6celzUvRKhzKziAgafRp0YNKBgylVBvgzyieRkGmEUH0pIDwurD6dcSJAr1TIqDbdoEizmeSZLK2ZjY6gRfO4O7ECXUoeTawlYDmcYqiV1FjYz6OTAZQDC4FbgCeEOLLmFELMAr4NfGmkC+S6ZE/duY6YDZO37qDCKibsR+QShmCWa4FUnSKI4PLOlbQbGgQCYAaYc3Az42q7uTm2mHPMKsKex+V1Z1MTSA26aj9SWU+f1On49SH0gMcio5qJ3pGlba3t8tqEM9lEH6dlHZ4qW8RpIkytA4GoQ5EHGdvg4cQaioJZKlxJxrF5snEDNzfFmShCTBcRCFgUR9IssC1MzUN6wnfJFoRKbFJ9Ft2ainH7yY7l3Fddz+lZBmeG/2nM4O9a4wSjNtPNcvQiDVOo6yAkgajq9FfGFjLBVZHIAOZXTcNCo8LxCEezPJRYzS1NcTaPP4txtssER1ARinKaq3NXbT2LvQghoXNbbAmb2/dSHk0x0wtQpFnslH38S109nhT8sFqtGOYEFf57TdW5GJbLa3YbZwXHEQzbFAWzGCi9tlZegrDUDEnT1UDVmihCZj06hUpDpZVE0ITkw50rCQQdZCaL9CRJoREwXBozIbSSELXxBqbv3spVbctwk+D5hrHTqrpICrUK0EyPwyLLtxLLiFrqA5WWLiYaL4V0or5+PBLKctg0iFRliQSz3NwU5+6aer6VWIaXVUiVpKaxwuugt0GjX9OpDKWIhjJ8qPYsejUIemBNLaYmpFReZ7kBgnh8Y1OdyrSheVhhlQlkiRtB0z30Io2wJ7m2TX2ALw5NGox4KEqjeEBrOsQGu3XwvZ9JmC/GLuC7iRV8IXYB4Wh2cOVWZUQoMoJUiQDfqqtHNz0OuH08Ub6EKYQwIyrmconU6O0PcFNznHJP2QmEVHDFkuIU36upJyzh3OYNPGklWVW5AOkJvtm4jA43xThH8Im6+XiOwJNQLiwsU/WRxyuWcn9iFU19nZxOhPWtu7krsZzbG+NY0qNb2nRqKprdlo59zJdFRCvSjHdUQt3TjFLSqCBJs7wgQSnp9CxSQlKnRbg/sYqo1Hiksp4KPcuXYxfiODr7HPWBv73xGHn+nQQ65uHoEPBrqehlFAqmEkAIMR7lXHK1lPL1kS6Q65KtaREqXYfD509lQSDGdJmkwnHRSkJ8rTlOeHYYo1Ilr2y6eIpyMbVt0A02xuZhBFy+k1hBrVRJeGpEkIrqPmZ+OcrPKpYymSSmf4OtSoEmYYGdYlJW9fZiYbOnv4RfNa6nU9ep0NVs0ZISsxhmZzPUVCuLdNXEPmwhBpdYj1YuVXW7GqKshMaeIqa6ac5rfZlwhc1Ldimn671YZZIt3eXMyijY3PNlF3Cfu4+MEERrlJvbQMCcotMkM70Aek2EgOYSLU/T3xbAqhTEHMHPEmspcxQyQGjwA72Y012DIumRSRt03azaFgrbVGkZah2HpaUzmJJ1uO46na80x5ksAxRJjd3TZ6kB1oMvZYqoFkGmZtW9Cnqwtnq+yqdoBTmv9WWsgMspRgnXpFWs4JKKFHstg+49JoRDaNEg4fIsuimJVGY47dIM31tRSxiBJwUUhZl8ZZDnyy6gtDaF8P9jSklZeZLLO1ciDI2Oq2byxtwZbIzNw4oZWOWCX5YvIVKewURF1NODcIarVktCSLSyEE80vsx/J17ib0PtnJXVCZVl0Q2PK/+xFCelUVqT5I25MzjFdn1IJoyTFqd6af7U/Bp2WhmLTdMlHM3yKafUVwU4aNEQ9xEiUmUzOWsT0W3SuBRJQUVdP3cnaonU2FhSYfN7Xtcodj3+WHY+p1r99ONQM6mXizpWs/kHGYLSY8bENqaZZWzp2IcUEPVggrR4tHIpDyRWYQQ8xjkqF2SVrxU84PZxe2OcyVt3cF+pS1h6lElB3fIG9jSWc5otOOiGeLiyniLd5qOdKwhJ2OQUowlJu489/3LsQp5ofJkL2tZRVKc+bGtadzLOsbk+YxKs8qgIp9ER/NYtoaQ6RY3M8L2aem6ILaLWE1wbO0/FtQEmFfVyiRNhgqPcsudVTuGvK5swwy5R3aasKMVPEmsGJ0UaUOI51JgpvtG4jMWuWuUuzqaQwO+sID9IvERFXR9nmZVvyh7zTuhknTH/BuXxhxBiGmABbUKIUuD3wG1SylVH+f8QOnz+0DRO7e7IBr3aPw01kJVWjuxZt+f+oYaQyi8fSaVzkKGxlebUDDWudf7dkWhajfrQ9kx204xEuRHYAD5QfiQq3FkVQ50gX2t/Y8Tr3JIXE6D0tKEaoQ985cije0IbGsGr9DtrR7zuT+8dijcaQJsAPBsa+hKWukN5B9RKoCz5uVS+YORX6eaPDzX4dP6xfQROhULJpYb0EaPTJ/M8I/MjfevTJw3u35UaaoBKP79lxDodMVTuOdYRw+o6a6gX4I3m0Chnd80/8t7cMjUx5Fzp3KH35OuVR6LNnXXTUGPa0VyNq52hARrP0EsH92/tGepFeeacpiHHlnHkGS4MDzUV3RYbOaLcj4NDjV5XVTWNwMmgw9UATbaPuNz/pm1omqkbYouGHOe+R/d7B4acuzpUULTht0V/8bEyRnDJ/hFwmg+hexy4RqpPy1eAKcDXczKZVI94cZ/Grd7D+qDOuNV7+EXHZnYEDHp0DftgLzfGFpHcmsTtcvhuYgVPlC9hj2VS/L+fVrEyegL0dQb5bOx8bm+Ms9/SeCCxisZECV3pAHstwTYtzGWdL+ElmujeozyjNgY84iFB60em0iNNeruDXFZ7Fi2G4KAM8Y/PltBkCKr/0ECDCXsbVWTT1gNFbLCCNNhq0G8w4VN15/IUbRTf/FvW157Di4EAm8bNo/twkJbWKNvdKL0HTVJJk80BQVNnlEOGxX3V9ew1Ja37o9xTU89n6hbwvZp6unepN93e30uLF6C9JYKbhP4DGm+Yku/X1HP3A5IG2U+2T2e/TPGV5jgNloGd1fn72IV8pm4BrR0RtmhhdlsGr6YOY+Bx2JDcFlvCw6ld3OEvCxPNxSR0yZpsI7ucLrZb0GEH2R3Q2ef6g36qj0+mBL3dQWYS5v01c0glTQ4fLiHqQmpXBtnagdebZtyqBpJdFr3NQRqeCSJ70+wUaXpSAWRrJ02Hi7mkcxW9LQFkZzfZN3ppNAz2NpbRYui47f1kE1lOfXUnn+pYTtcWQc8bahTubAzTI1RG8N6DFi+ILu6rrqc9HSL9xy0sqp4JwGfT8Irl0Lo/yt6OUlati5FN6rQlivhhaw3PBT2e1rrIdmvslH28agZV9MJYhrZUiLbeMIebSthst/E72tkVMMhub6GtN0xPIkBS6FzYto5sq1petzdG6GkM0rU/yA7TZfvkM0jvy3LI1GnVLOY3beCGlhCdiTAvlp+P19XDYdOgKVHMAbePp1N7Oah7bNezNAqbq9qW8Ym6+fR1BngmJHmKNh5KrKYl08V+meLq2HnsnDIbw9fT7tMc3pg7g/b9EfaYkiqyXNsWJ5EJ83BlPQ2mpLs/SF9/gKezB+jUJM2Hirmnpp7HKpbi9Atuji1mXuUUdlomy/v20rU3QFMyzF6vl47WCC2Ho2wxg9zUHOfXvds5qHvsc3u5qTnOPTX17Okv4fOtcfYbFjssjz09h9mipWneW8whGaK1N8Kf0vu5tSnOJbVzuaUpzgNV9fTYFtfHFtGe7eVjdWezRQ9xyIQdneXcEFtE86FiXrFbB3Xkx4JOVpfsrJTyb6WUs33X6xd93m9KKSM5mU3OHEBsvBWNdwRbJ81lcdkMyl1o1wWapVGEjueo6HIDFPag51uXgechNBVWsN8P+xz24JzKqcrjDo0tqOwgfyi7EKSHGXJJ4lIqdSqkjl5u0aWrgfASWUqL5lHmKzRvao6z76zpaKgsH6DUAyWuWvJ9MXYBta6gRJhM0Yvpvn0x85s2MDBH0XSJqbuDGUwAKjyBjiTsSWzfLVtKwY3NcR5vXEdYghV2ubD6dAAi0sUyXDI9OtmkQVgKzrDTnOIbA42Ah+4Hjg9IFRDpvxMv8XjjOvpdZags8mB8oJxNAYtvJZZxV2I5USPEF/0ZcMh0+EbjMiaYpVTqYXaTIiQcXFQ85FNL1KxHIJESdorUoLeaoXnYAswyCZYaPDePPwvH0dB0SU9WrTZS0qHfX8K6nnJ6iZRnwTQxyg2qHZeoYfOF1rjy6vTpkcp6iupsjIDH3TUKsZJGcmfdUqyww2JK6dag2MjipVVWkq/FFtOBhYkgEs1QpmeZd2ozVtjF9TQuTHmc6pn8oWkTQoO1vXuZYLsclima9kTJopGVOgHDYZwRZc7ADFUDS/OQUtBmaDxZvhg9IPlY3dmDYWMB0igePajCupZ46tzq7j3M3vcqF3WsBtvhupY4nhQUaxbzguNUhhZ0ev0Yyr9qXE+kJIOFhvCfcU2gjFNEiJ8k1uBJwYbkQTJ+ogEr4g5G9BvoLX2aRtjzOM1W2dg9T3BxYDztwsXQPVZqfZhSkk3qfCexgp3dB3EE9GT70U0PE49SESBjG2QdnT5NheKdER5HVGpU+VHvbmyOI1Ez/y4d6lyNSUU1jJcBFZ7Ab0+tWcKF1adTIixuiS2hyFORBjtklrMjE7HQkUJlMCmSLjXSIBS06XVT/LJ8yaAh+53SyarKOKa05ZS5fKE1jtAkO1JNNBkMxmf9VmIZ6V6Dvn3qxfxUx3JadfCa20Eqi3syafFE48ucWXEa17XEeb2/kUQmjInHfBmhzRD0C53Gn7cihOT+xCoahc0hoWIFRzyPZFale5+TEWy3THpxuLNuKZM27aJICmzfPbe7O8h202VCtJLDXpLrWuL0Sof7E6so+dYKniu7EEeoUJCeK/ipHkKiQPbBoO3r9wSmlMol3BVkbJ3v1dRzX3U9toDe9gAT9GKq/9BAFo101sAqcgkUOWwlyWfdfRw0ISpMGnZWAnBt7DxadJWho/2KGXyjbiklZoaUgEYDljVvpVFTA8TVsfOoMoq4P6HULrrm8bnY+XS4SV7q2cPjjetUCiUBjhCcEqyEYJhLOlcRDNmDy7t01kBKQcxxsDsFXls30vE489Am7KwyAhZbWdwum5AwiOo2Mm0zvb6L61virGuoUx/XoIEnFFplwOlCOspV/5q2OG4aAqWusvz3hmgli4FCIHRrkhbNpcex0IvUO3K3n5i2FZupO7bT55qUXj4BzxU4rkZNIEWnpmZC6V6D8cFKNAkTRYjy2n4OmgY6HhnH4BeN64lIjZub4nhpSbdrYVgu7X5I1CWb06SlOxjgv7cvSC8OdlYn06mREdCu6/yqfAmxUMVgZurSezbwQFU9TV6Q3zS+wlwZHmz7mV5oMKxAa2OUsA+R/ELsAja2NfDHzEEuqZ2L52p8JDKVTg022q0kO02yGYMK3w3927XKTbpUOhw0JN3pAFlXJ55NUCF1Xk8pA2SfptHXGeTG2CIWV5xOSEJXWqVh68egXFgckCGynkaRB19pjlOthUgIFSv6ythCHxYo2eC082u3ka81x+mwe9lNEk1I+jRBSHd4sXkLpxgl2Hg0k+WK9mW8VLmAmYR5snEDL3bvpMhVzl1PhDx2izSptElUD6EjSYljM1D+xasy3u00o2HrWzP5VPuh8FszFUCTncJBO58V/QXzXncUsP1o6O+XjewMkE+zyk85JnWOhhJrC48u9zPfC/OdUmrFvoJ5px7FwSSfVi4cNg/EqOmOlpEdffKp3Bg5K8jxoilm4RlEPmgcmyiOHz2ODiYnK475mFIoYvNgVT2z9r7Gnq7DVLvQpoP05OAMKlTt8rnY+TxWsZRyV8GNpGuza9psIhHVkWpN5enXmepDR1Jk2rio4DBB6YGhDTqrAEx1Tdo/PQNQGNtF1TMxpaTWkdx9djvVrmDXtNnc3BRH92dYoaBNhw4He9v4fdMm7q6p5/GcVEWm8AhIwUuVCwhGFURIAMGwzYyGrQQQFJlZSqRNQMI+w2Nhy3puao6ztGY2RS4YhkeRMGi6eAof7lyJ5eOYjYDH443rmBys4ssXNaEBSzrW8FjjOibKAOMcCFs21X7SGF2T1Doe1kB2CB8D3SOzPN/0Kl+LLaYt042mSR5KrMaWHouLlSE268eyjkqHdrsP/ChzrqNx0O1hSmkMQ/fodwxsBK0HihABc1ANoesenqtRHE2jFRuc5Qa5sG0dImwpdAYws6wDUVwEniQgFYww6AGaQC9ShsmglFjVChNc4Sq1S+lg1j+V1WRuVieDGPR4VDFPPEwE+8+eTkS30Swwwy665lFalmS8q6IFGpbHhrY9mEh6cMkmDYqtLKXBDF1SYYgFChVhVls4KPVRcqDDajBOUx98M+gQLUpThkkobKMZkvG2cq4ISI9nTg1SFMnwq/IldN28kBrHYXK4h/lV0/hwzZkk8fhs7HxubooPprsKh7ODcb/bfJeAZc1bGadFKCpT6jVHwAyznGDUwXE0dBRayBZQV9RHCp1iKajvWEPYstnY1kClJ5T7v3S5ti1OpCRDqdTpcVV4plnlpyA9tWI67CUJBW32a8FB3P22bAs/SLzE8pZtlGNS5UIIl2lGKTpwT009h3vbmSCCWJZLv6ZWRABRlKPJRBngm36gLEsq1/SLSmbQpav/l+tZhVPXPIq0AEHpUeEdmyHrL37GPFysDCHE/+QY9/b58ZcRQlQIIeJCiD4hxPcLbcSU7dvRgG2nKbdUU8I4B/RSi4Tm0tsdRA9rnOEGuKJ9mcpyUVqMCESYvnsr4eIsn4udz7NNm3muTBm+Ti3rJmC63NYU56y0jYWHVlWOndT5Vl09NdLgpuY4Ff+zE4A5BzezsmU7n+pYzkSR4j9eiWELCEZtHqiqHxxMrIBLtQtTS1XuwVJXxcu4MbaI7tsWUWRmOcUR1FT1oumSilg/5Z5NpDLD9slnUO6qDCb9GJS5KhLY7umzeLiynmXNW7m2LU60NkMaF7PW5JmyRURL07i2huu7PZVpQV54toZSTBqXTFEOH6j0WcXFae5NrOTOxmWYhosExtsqFVa1o2agS71irowt5O7ECpr7uzAMlZBgXesuyoTSCQ/ojjUkswM1kFIzJk2XnGKUcFH4VMoqklRGUngCxp3Vh4iEEJbKKhMtT2OFHJJJC2H4yXInnwGmgSYkz5QtwnM1ZGc3TlsGG0EqY3Kq7aCVhKj+vULfpIXAS6rMude1xAmHs5RJnbQf5e2AyJAVyuts4CNrIpgY6WOyVBk4Lmxbx95XyvBsQco2+U1nDQEPnmp8hVClw+di5/PBzpU8kFhFyWSblK08BE8t6uGS2rnYAmociQgYlGo2niOY5AgFwfQggq6iHAY9IuVZTAR2VidYJ7iyfRnlnsoycmuilBkNW/lEx3JEwMIWGs39Cgt8wO6mVhr8OLGaz8bO51/q6vl2bT2G4RHwu+mTjRsGM5nP9AIIDXpwmJyVlGCgGZLSqiR7dZer2pZxR2OcN/qKqdAzg+muTNPlE3Xz8U0UVGgB1lSdixl0+efGZUQ0i4CEhUH1ftdoaaq1II6jMcfq5mvNcb5XU89r7W/w9bqlXFI7l/9KrBxMsbYydWAQa3xxzRxCUsNzBdOzNv3S4MrYQmw8vhi7gG82qjZe0LaOW5viRIWBKTTlpQhkPZ0e4eF6SpVzWedLFB8jW9yx1DELIS4VQuwSQjQIIW4b5nzAHzMbfKe8SW91zbcVK0NK+ekB4x7wK+DX/qk08E/A/yrgukPo71rj1JydGdxPCdAn1XJZymHSB7IIS+Nrfn6yvaYEzwNT4To37K8djC38gc6X8FDur+msmuVd1vkSBwyLzl+8TmS8xzaRQvPnXB1XzWS8kaT5A1NYU6UyZFWU9vPtxHK+1hznlFd2MZt+FrasB6BkXJoLwh3s6TrMd2rrubYtzsK0yz2JlWinT+fc5g2YUjJ1x3asqMfehgqKzSyaAZXTUoy3XSzLJSMEf9ca59amONN2beN9Uw7xXNmFvFh+PnXLG3g0sZaKn+3gg50rKaqzKbkgysQNuwdxxWHP5b8SKwnOKmauY3Jn4zJm1rUzffdWld0DOPPQJqZFuhkvM0wP1pDWlBekKeFnibXcXaNWI6W1SW5tUjP2HqkGqgHI4vs6V9PsJRE1kwCVhWSWDLHP66Pi4ihnHtpEUHoEP3wuoraa8ke2MWX7dvq7A5ghl4q6fsof2cZNzXFmvr6F0u+sxQo4fLBzJWXj+hFFEUKXL6DaSCOE5IOdK9FnTqHrq+pZxGQGozaIUa1WAdWzUnyzcRl1riC6tJYpMsgXWuNMO70VY4YaTMbLAM86pdQ7/QQqVE+eskRB9pZ0rMFDZY75f7X1GMUaDyVWs3XSXABEUEX/S7s6sYUpAuiUeIIr2pdR9uBrTBjfRfFsZcz6eMcKvvvqOFpllvJJKYI1kmCdJIVH1dR+9Loini+7gLJAhss7V3KxE+aZskU8XFmPqCijkiwf8OFil1rjKfLgvup6wuiUu7BDS1PzoQj/lVg5mMbMli6PNa7jlqY4RTM0Ppy2uKJ9GVd6ScKzw0zatIurcxKXHvJjkZe6klWVCzhj/6v8qnE9Jb6t8tJMgPNaXyY6R/WlTHSOdgAAFGxJREFUT8oKAh40eSl2v17JpCkdPJRYTe3UXvanFQRxgq2cuLqEy4QcqGazbvKwqQzFs+0MF2sVlEhBtDxNr9BZ+L4W5nkhohhMkOr9eqlyAdsnn8Gn6s7l4cQaznNDmFIyx85wUcdqPpq2B1OQbZ00l1PtoUmU3y550it4OxoJIXTgXuAyYCZwhRBiZh7b54BOKeUU4Hso57uj0tuNlTHQKAF8CnjM5+2XUr6EGqALpp1TZvPNuno6t+osqVYZlfs0sLce5MWQRdtqidvjcGtsCb8sX8I4V0AmC/3d7Jo2m+lRBV37+9iFPFJZrxwiUHGMv1NbzyOV9VQ7Dpk+g74DOj9LrKVHeHzPH5j2eBF+8uoEbhP9/LC6ntXdVVxcM4e7a+p5ffbprM95+WrjDbyQKqcmUsrrms191fV8sHMl86umEb3mQZ4sX8xVbctYWz2fnkSAXwYNdnlFpDoNuvYGaDF0OnpDBKXHfdX13FNTz8s15/D86+Np0wy2mwF2T1f3oOUyFRiodU+EP/00wv6zp/OMrtqy1zL4UO1Z9G/s5bqWOLfFlrCmpZqXa87hHy5p5dbYEjbG5rElWcqyQIBNfftpGYgpovcwr3IKh3WPl2vOoe2Q6nDVWpioMHgosZpyPUuPBr8sX8KLzVuQB3bydNkiNtSdzesig45G4ukUa6vn06ybNH53M+72Bjo/P4c35s5ACEnrwSj73igHVMwIUGFWqxfBk+WL6W8LIPtTZP64gYQbIuko1YGzbiuZ7R3snj6LlDTI7E2T2qU+2m+8XKKiqenQ+MtO2oTLHXVL2bG9muzmA1xedzbfbFzGWRmbuBGhZae6X+bsCfR3BHi55hxubVIf/lua4qQOq6BAs/e9yg2xRdgtKvlBFya74qX8rmkj3Zrkh9X1tH50Ks2NUTo3CQ4Zkl+VL2GvTPFY4zoObiulfUeAvn06Fho1LzTQ8GuNRt1it63u709FC7Whfsa7GbxDTSzpWMOqygVcGzuPJB6dmmSNoVY82wybrdk2mn7Xzw2xRfT5WJ/W7BFMeOs6nXjQ4/s19fxAs+h/Lcme02fyJ6+Ehyvr+X+19Uy3M/S4Fi05LtnXxs6j0VBJfff7Warb17rcHFvM83ofXTr0eVmmTW7jlV11zK+axs27KolI1YZPdiyn1ennnsRKNmUV6Or7NfVM9DL8wgjxsbqzWRsI8KPULjZrKTpbw6wOSnbGSwl6UCF1dosU36hbyjYtTFtXhLNlhCvqFrBDd+jQNS7qWM31sUX8PKjhetrgM1oTPJIh/J3QMZwxnws0SCn3SimzKPjwR/N4Pgo84u//Erg411P6bTcQmARsHaZ8MbBhmPJrge+/xTW/CGzwt0dHcZO+eCL4/lKuOVb3e6vuk02e0dT959ryxqoNuW0EPgk8mHN8Vf7Yh8qJOj7n+HWg8qh1FtiwkQbm+4Cbhyl/y4E5j/9Ng/s75T3WfH8p1xyr+71V98kmz2jqfjdsx2tgLjxIbR752bD/Cjj7rXjHaIzGaIxOUjoMTMg5Hu+XDcdzyB83S4CR4xLwzuBy7wN2SikLTz88RmM0RmN0ctF6YKoQ4lQhhAV8Bngqj+cpVOIQUDPsF6U/dR6J3m6sDPwGPDYM/z7gu8C1Pn++hXI4ur8AntHyHmu+v5RrjtX93qr7eFzzL6XuE05SSgcVI+g5YAfwhJRymxDin4UQl/tsDwEVQogG4B+AN0Hq8km8xcA9RmM0RmM0Rn9meld4/o3RGI3RGI3RERobmMdojMZojN5lNDYwj9EYjdEYvcvobcPl3gkJIWagvGHG+UWHgaeklDtORHuOFQkhygGklEdNvVAo34mmk02eMRqjvxT6sxv/hBC3AlegXBcHoHbjUSiPx6WUd/l8BsrH/ONAzOc7DPwWeEhKOTTnz+jaUEPOR0FK2fx2eYUQE4F/By4GulDByIqBF1EptvaNhi/nugLl7pn78Xp5OJhNIfIUer3jIc9oZBmj9xYJIUpQsXhy343npJRdI//r5KcTMTDvBmblD6w+BnCblHKqf/wYqsM/wtAB/BqgXEr56bz/v2XnF0KcCfw3CuA9AAIf79fzZSnlxtHyCiHWAHcDv5RSBRPwA5v8NfA1KeXC0fD55ZcAPwD25NU9xa/7+VG2saDrHQ95RlO3z19wRxVCfAD4WB7vb6WUz+bxFbRCG81KbhTXLEieQmU5HvKMsu5jJo8Q4mrgTuB5hr4b7we+IaX8SX797xU6EQPzTuADUsr9eeWnAM9LKaf7x7ullNNGuMaQc6MYyDYDX5JSrsu73kLgh1LKuTllBfEKIfYMfEyGaefguUL5/OMdwGXDzKJPBZ6RUp4+yjYWdL3jIc8o6y64owoh7gamAT9h6If7amCPlPKrPl+hK7SC+EZ5zYLkKVSW4yHPKOs+pvIIIXYBC4YZ1MuAdSP1//cEvR3/8Heyob62DcAfUGDy+4Fn/bJLc/jWomZfWk6ZBnwa9dByr7kDmDRMXacCO3KO9xylXQ15xwXxol78HwALUCqXmL//AxTYfFR8A3UDxjD1Wnl1F9rGgq53POQZZd27gNJheMuA3Xllu0eQW+TeF2A3YI5Q/6j5RnnNguQpVJbjIc8o6z6m8vhtLBmGr+Ro7/Z7YfuzG/+klM8KIabxZrXDeukviX36DCpu6b1CiIEvaikQ98/lksGRL3MuHQZy4wT+QQjxe9SX/KBfNgH1Jc9fthXKezVKF/6NPHmeQnn8jJYPVBby9UKIx3Pqnoj6KOXyFtrG4a43AXUf8+s+1vIUKguojjvcEs7zz+VSWggxX0q5Pq98PkPDznqoj8b+PL46/9xo+UbDW6g8hcoymroL5RtN3cdann8FNgohnmfou/F+4F+Gqec9Q+9azz9f53wFkAA2ombaFwDbgPtljo5aCPGPqLjQw3X+J6SU/5bDexnD692eGaYNBfMeaxJCnD5C3dvfTht91/jL3+p6x4NGIcs1wNdRS+U3dVQp5cM5vPNQ0Q2jHPkoTwC6geullK/4fJcC30fN3HOvOQX4ivR1noXyjfKaBclTqCzHQ55R1n085CkDPsCbddadvIfp3Tww/ww1Ew6hHmgEeBKFAhBSymvy+Avq/MPUUy2lbHkH7RxAj7zJ0EEOekQIcRpwh3/u26hMBueh1DC3yDwd7DD1VEgpjxqRyud718tzNFlG21GFELW5vFLKpmF4NN56hVYw3yivWbA8hchyHOUptO7jIU/BKKn3DJ1oXcpIG/Ca/2sAzYAuj+ipXivg/xXDlJUPs+1D6cjK83h14EuoJdX5eefuyNl/DDU7WIgycIz39+8D/ieHbwVwHSqAyVZU+q0JqEHwxbzr34UfrxUVVnUvauazH1gyWnlQMLZ/Ax4Frsir6wd5x8dUnkJlOcpzvPwtzg+nR63MOxYo/fdf+dsC/ElJHt9EfB0qKgb5J1EIordq4xTgE8DMdyJPIbIca3lQOmeRc1wP3EyOved4yQOcibIl7QBeAP4I7PTL5hVS/8m6nfAGHOWhbvVfmjKgd2CgAYLkGPT8skIHMg94I2+z/d+9edd8EPg58DXgFeC7Oec25uwPa+jIPwdsytk/kMe3Ke94S85+HJjv708jJ5B4ofKg8jLehZoFP+UfB/JlOR7yFCqLX/ZXw2xNA/t5vPWoZXIbamk9aYTncwlHjM0P+tuAsfmSHL7b/Pu2E/i8//sQSnX2D3l1x3Pet6tQRqwHgS3ADaOVp1BZjoc8wKtAmb9/C7AatRJ6Afi3t/N8RvFsNqNQGfnv2ULg1T/HOPNu3U54A0ZsGNyEGmD3AzcCfwIe8F/+O/N4Cx3IbvZf4jNyyt4Yof7XcvYNFHrk10CAoQNPQegR1OA+DWUAaQPO8cunkLcCQM0gjIHrH0XWguQBNucd/x9gFVAxTMcfrTzn5skzNe/eFSSLf2wDT6MMhj/2t17/90d5vOvxZ3+omeAeYKF/vCmv/knD3JN8xM42lNqswq+zyi+PkJe9J/fYb0eFvx/Ok70geQqV5XjIk7e/AQjlvPP57+UxlYdRoKTea9sJb8BRG+fDsPz9Uv8hnzsM32g6/3jgF6iY0VHyZso5fDuHKbsTNaDlQn4mAf8DtKJmTnuAFr/s1By+i1Fwox3AhahZ6wDvx/LquQE107gI+L/AfwJLUAiIR0crj1+nlld2rd959+eVD8jT4suz+23I89G3Kct81Af4upyyN0Z4Pq/mHc/y2/Mxhs7KCoUeDqjOdF+G3A9T/sC8CRjn78eBYM5/t41WnkJlOR7yoGbIs/39Zzkyew4OI/cxlQe4B/g96qN/vr992i8rODXdybi9a41/oyEhxA3AR1DL9cUo9cevUYPBaVLKq4b5z+XA7ajZR+0w538K/FS+2Yvs88B9Uso3pesVQlT4u/8ppfzbAtr9NEpH96Yc6UKIpSgd7jTU7OUg8Bvgx3IYd/SjySOE+HeU884f88ovBf5LDnVuKQgNk8N3WEr5RyHElcPx5ckyFQVfPIgyJv4oXxbfYHUDqhPfinKGOG0YeTcAH5Y5BiUhxHjUjG6ylDLqlw2H2BmACg4idoQQD6MGtwiQBBzUQHUREJVSfipPnntRH6NyYB4qUPqFKEPYf4xGnkJlOYo8b0IgFSqPEGIOyvbwqn+tC1D2gzNQ6ruf57X1WMtzwpBP72Y6KQZmOOpA9iOpsgwM8M1AvQTrABf1omwVQlw6zCB8LiCllOt9uNmlqJn0Mzk8+WlkQL38L6L+fPlo+EaQbRFKZbBFDnWfXoBavvYIIcKoGek8lJrhW1LKbp/vRuBJKeXBN138zXUVhIYZDWrGR3B8AjUguqjZ08+llD1Hacc4FNLjnBEG5vcBrVLKV/PKS1BwsH/NKXtLqKCPRvlrFE73l6j7/TfAAeBeKWX/MPX8DUfet0Mol+OdI8gTQ7mwv0meo8hSioKX/Wte+VsikIaRZwHqQ/omeYRypb8kT5ajxqs42vMZrTxj9GY6aQbmkUgI8Vkp5Y/9/RuB61HL7zOBr0opf+uf2yilnJfzvzuBy1Av6guoFzuOwmw+N/ByCSE2AttRRhiJspg/hu8EI6Vc7vNtQs0mj8rn874spTzX3/+83+bfoDrP7+QRd9ptwFwppSOEuB/oR83iLvbL/8rn6/bPve7X+QspZesI9+s1KeUcv2MfRqmSXCGEQC1R54yS76vAh1CzsA+i1ABdqOBUX5ZSLjva8zvZSAhRI48xHGwUUMqC+P5c5H/c/hH1kalB9YsW1GrqrqN9GE56OtG6lOO9kYMYQBkOi/z9SShjx1f94zchI1D6uTDQAxT75SGGGng0lKHyBeBMv2w4PW9BfPltQRlScg03uca/XGNPvi5yc+71/PovQVnmW1HL2mtQy9rc/xWEhhkF3xaOQB3DwDJ/f+Iw97wEpY7aCXSgMgnv8Mve5Ap8lGf+h5z9gqCCeXx/MxKff1yLgg/eizKu/V/gNeAJoC6Hr1A446V59+Ah/3o/B2ry6i4UgZTLd85R+DaiUBiTC7iv56AmJz9FrX5eQH1k1wNn5fAVAf+Mmoh0++/bWuDavOs9h1KH1Obd29tQqrcTPn6cqO2EN+CYCKFe4uG2LUAmh29b3v+KUAPUd3kzcmHTcPv+8eZh2jBghPs+efCx0fLhQ5j8Tp8PKctt1y+Az/r7P+YIMmIaypFggC9/0DZRS/vHUEvO3HMFoWFGwbeFI9C8MoaiZPKNSyN11FvzOypKZTPcdjbQmMNXEFSwUD7/+FmUnvU2/z27FTVQ3YBSZwzwFQpnzG3Hg8A3gVP8e/ybvLoLRSAVyvcG8B8oFcfLfp2xEd7Ll1GryCtQqsJP+uUXA2ty+H6LMi6PRyUf/SeUfeERlIptgG/XUfrJiOfeC9sJb8AxEUI5oJzpv8y52yQgkcP3Iv5sNafMQMWacPPK1wFhfz/Xol2S31Hz/veh3Jfv7fChZlV7Bzow/iwM9SHZnNeWh1EqinV+p98LLEepMgb4Nh2lHeFhygpFw7wlH/BV1OD1AGomPPAhqQJW5PEW3FFRuuoX/UEnf0vl8BUEFSyUL/9+8mYMd+7zKRTOeLR25B8XCqUslC+37kWoIFRN/n384ijkzj2Xj8pYP9CPyEE7odA6/5ucVQFKpXEr8Me36kMn83bCG3BMhFBLvwtHOPfznP3x5MzG8vguyDsOjMBXmdvR/sxyhsmBrOWUFwNzUbPFmmHOTzvBz2eWP2jPeAu+gjsqSpUydYTrHMzZLwgqWCifX/5qzv43886NGp6JMrb9gz+Q72WoJ14+lrgg+OEo+N40yUCp8C5FIYByy9eg1GF/jVopfcwvX8LQWfjqgf6IWpk9l3NuV85+GcqdfyfQiVJf7fDLyvPb9V7aTngDxraxbWDL66gdeR21LI/3k8D0Ea7zsZz9fwfeNwzPpQzFoxfE55f9M76tIq98CipxwHBtuhylZ20a5tydeduATaEW+Mkw/EtRuPJNKFXRM8AXycM3F8KHgrsV+nzmotRNfwBm+IN9F+rjdX4O3xyU2qMTeAl/YoBaJd2Yd80ZwPvy7ycFuoSfrNsJb8DYNrYVsuGrQI4l77HmeytelOF49omo+0TKPRIfyjaxC4U42sdQx6QR1YXvhe2kh8uN0clBQogDUsqJx5L3WPON1T26awohtgDnSSn7hBCTUHjrR6WU/ymE2CSlPKuQuk9GOiFZssdojIYjIcRrI51C6ZpHzXus+cbqPqbX1KSUfQBSyn2+k9gvhUozl58Y4T1FYwPzGL2bqAYV6zc/tq9AGZTeDu+x5hur+9hds1kIcaaUcjOAP3P+MCpI0hm8h2lsYB6jdxM9jTICbc4/IYRY9jZ5jzXfWN3H7ppXo2J4DJJU4ROuFkL8MP+/7yUa0zGP0RiN0Ri9y0g70Q0YozEaozEao6E0NjCP0RiN0Ri9y2hsYB6jMRqjMXqX0djAPEZjNEZj9C6jsYF5jMZojMboXUb/H7HU87YN33KRAAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# heatmap of log trans, zeroone, and z-scaled data (before)\n", - "data_before_pca = log_z_zeroone_na(x_50_before)\n", - "sns.heatmap(data_before_pca)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# heatmap of log trans and z-scaled data (before)\n", - "data_log_z_na = log_z_na(x_50_before)\n", - "sns.heatmap(data_log_z_na)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# heatmap of log trans and z-scaled data (after)\n", - "data_after_pca = log_z_zeroone_na(x_50_after)\n", - "sns.heatmap(data_after_pca)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/tzx804/env/fixjupyter/lib/python3.7/site-packages/ipykernel_launcher.py:6: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", - " \n" - ] - } - ], - "source": [ - "## PCA\n", - "result, args = runPCA(data_before_pca)\n", - "result.set_index(x_50_before.index, inplace = True)\n", - "\n", - "info = labels[['index','MS_instrument', 'LC','ColumnLength','shortdate']] # i have not included pid because there are so many different..\n", - "info['ColumnLength'] = labels.ColumnLength.astype(int).astype(str)\n", - "info = info.loc[x_50_before.index,:]\n", - "result_to_plot = pd.merge(result,info, left_index = True, right_index = True)\n", - "result_to_plot = pd.melt(result_to_plot, id_vars =['index','x','y'], value_vars =['MS_instrument','LC','ColumnLength','shortdate']) \n", - "\n", - "#from ggplot import *\n", - "#ggplot(aes(x = 'x', y='y', color = 'value'), data = result_to_plot)+geom_point()+theme_bw()+facet_grid('variable')" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAtoAAAIhCAYAAABwux3pAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdeXiddZ3//9d9nyXnnJyc7FvTtOlGWwqlGzsWCijCsMumiKAzirs4jg7KsCl+WXT4XTOjjs41jMqgMAgIWCgK0haBYqVQoCvd1zT7dnL2c9+/P9KmTbM0S++cLM/HdXWG3J879/3Ox+Tkde58FsO2bVsAAAAAjisz0wUAAAAAYxFBGwAAAHAAQRsAAABwAEEbAAAAcABBGwAAAHAAQRsAAABwAEEbAAAAcABBG8C49dvf/laLFi1SMBhUeXm5Lr74Yr3++uud7Rs2bNDll1+u3Nxc5eTkaMmSJXrzzTc723fu3CnDMJRKpbpd+5ZbbtG//Mu/dDl29PlVVVXyer2qr6/vct78+fNlGIZ27tzZeS3DMLR69erOc7Zu3SrDMHr92qqqqvTKK690O75ixQqZpqlgMNjl36pVqyRJ5513nnw+n/bs2dP5Oa+88oqqqqq6XOeJJ57Q6aefruzsbJWUlOj000/Xz372M9m2rYsvvrjzuh6PR16vt/PjL37xi1qxYoUmTpzYrbbzzjtP//3f/93r1wQAow1BG8C49PDDD+u2227T9773PdXU1Gj37t368pe/rOeee06StG3bNp199tk6+eSTtWPHDu3fv19XXXWVPvaxj3WG0uNhypQpevzxxzs//uCDDxSJRLqdV1BQ0C24D9aECRMUDoe7/DvzzDM727Ozs/WDH/yg18//13/9V33jG9/Qt7/9bR04cEA1NTX6+c9/rjfeeEOJRELLli3rvO6NN96o73znO50f//znPz8uXwMAjAYEbQDjTktLi+666y799Kc/1dVXX63s7Gx5PB5ddtll+tGPfiRJuueee3TmmWfqhz/8oQoKCpSTk6Ovf/3ruummm/TP//zPx62Wm266SY8++mjnx7/+9a/1mc98ptt5N998s95//32tXLnyuN27N1//+tf1+OOPa9u2bd3aDvXdz372M11zzTXKycmRYRiaP3++fvOb3ygrK8vx+gBgtCBoAxh3Vq1apVgspquuuqrXc15++WVde+213Y5fd911euONNxSNRo9LLWeccYZaW1u1ceNGpdNpPfHEE/r0pz/d7bxAIKDvfe97uuOOO47LfftSUVGhz3/+87r77ru7ta1atUrxeFxXXHGF43UAwGhH0AYw7jQ0NKioqEhut7vXc+rr61VeXt7teHl5uSzLUmNj43Gr59BT7ZdfflmzZ89WRUVFj+fdeuut2r17t5YtWzak++3fv195eXld/rW3t3c557vf/a7+8Ic/aP369V2O19fXd+u7s846S3l5efL7/XrttdcGXcOR4+MBYCwgaAMYdwoLC1VfX9/jJMZDioqKVF1d3e14dXW1TNNUfn5+n/dwu91KJpNdjiWTSZmmKdPs+tJ700036be//a1+9atf9Ths5JCsrCzdeeeduvPOO/u897FMmDBBzc3NXf5lZ2d3Oae4uFhf/epXddddd3U53lPfvfnmm2publZhYaEsyxp0Deecc86Qvi4AGGkI2gDGnTPPPFNZWVl69tlnez3nwgsv1O9+97tux5988kmdeeaZCgQCfd5j0qRJnauGHLJjxw5VVlZ2C9qTJ0/WlClT9OKLL+rqq6/u87qf/exn1dzcrGeeeabP846Hb3/721q+fLnWrFnTeexQ3x2aNAoA6B1BG8C4k5ubq+9///v6yle+omeffVaRSETJZFLLli3Td77zHUnS3XffrTfffFN33HGHGhsb1dbWpv/4j//Qo48+qgcffLDL9eLxuGKxWOc/y7L0iU98Qi+88IL+9Kc/KZ1Oa//+/brvvvt0ww039FjTI488oldffbXbk+Wjud1u3Xvvvd1q6EkymexSV19P8HuSl5enb33rW3rooYe6HLv77rv15S9/WU899ZTa2tpkWZbWrl3bbfgJAIx3BG0A49K3vvUtPfzww7rvvvtUXFysyspK/eQnP9GVV14pSZoxY4Zef/11vffee6qqqlJ5ebmefvpp/fGPf9TZZ5/d5VrBYFB+v7/z36uvvqo5c+bo8ccf13e/+10VFBTozDPP1Omnn97jBENJmjZtmhYtWtSv2j/5yU/2OH78aJdcckmXuu655x5JHeOjj15H++mnn+7xGt/4xjfkcrm6HPvOd76jhx9+WA899JBKS0tVWlqqW2+9VQ8++KDOOuusfn0NADAeGLZt25kuAgAAABhreKINAAAAOICgDQAA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i8XU2tqqT3/603rsscckSVlZWfrsZz+rH//4x8NWE0F7BGjf2Pdi/pENYYL2CNTW1qb169dr//79Mk1TkydP1uzZs4dlOErbu61qWt7QuXOZJEU2tSt7TlAFFxV1+8U6adKkHid8HVJUVDTgp9nt+/dr13MrpC2VMgxDnuygPKEc2Qkp1ZKUbClRm+j4/wfiCn/QppLryuXOcWtXH2MlJWn37t0E7R6kEwn97b771LptW+cx27J04K231Lx1q866/355x9CbSQxcojauljeaFd0ZkayOYQ85C3KVM3/0/hXveAtOnKjgxImZLgMOuP/++3X/wY3bVqxYoR//+Md67LHHVF1drfLyctm2rWeffVYn9bCkrVMI2iOAFellivNB6WjPS08hcw4cOKBly5YpmTy8pmptba02btyoyy67TDk5zi1XlaxPdAnZVtKS1Z6WnbLVtKJeB974m2r2PSe5LJWeeqqqLrtMheXlmjx5snb1sKGNYRiaP3/+gGqoe/ddvfvjH8vvPkGh3HJJtlIN9Uq0tcrrLTn8BsCyZacsGW5TycaEtv/0L9q79TeK7N4tn9er1IwZSs2cKZnMQ+iPA6tWdQnZR4rV12vXSy9pxvXXD3NVGCkStXHV/F+17MThd+Cp5pSaXm1QqjWl/HMLMlgdxou+Jipmyo033qi6ujrZtq158+bp5z//+bDdm6A9AniKPNKHfbSznNCIYtu2li9f3iVkHxIOh/X666/r4osvduz+4Q/aOoNsOppWurVjVzXbsmQlkzIjJcr3flR1Tc9rzyuvqPrNN3XaPffoggsu0BtvvKEtW7bIsjre3GVnZ+u0007TlClT+n3/dCKh9//937V7epmsCSfopH0dT8LNtKVAxJI7mZJ55GQyw5BtW2rfv1/pREqptri8Xq+S7e3yrF0rs65OiY98pMvyWxOH4WlTIpHQvn37ZFmWysvLFQh0HXYTi8W0efNm1dbWyu12a9q0aaqsrMzon+EPvPVW3+2rVhG0x7GW15u6hOwjtb3Topx5OXLnsgEPxofzzjtP5513niTp1VdfzVgdBO0RIPukHLWubpGd6vkFMmee84v5o//27t3b57bMe/fuVTgcdmwyX6qpI+Dblq102+Gti61Ux38bhktuV55C2YvUHH5dqUhEGx55RGf84Ac699xzddppp6m+vl5ut1ulpaUyB/g0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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# take a closer look at each\n", - "date_data = result_to_plot.loc[result_to_plot['variable']=='ColumnLength']\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y',color = 'value'), data = date_data)+geom_point(size =75, alpha = 0.8)+theme_bw()+scale_color_manual(values = ['grey','brown','mediumaquamarine','mediumaquamarine','orchid'])+ggtitle('COLUMN LENGTH')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAtoAAAIhCAYAAABwux3pAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdeZRcZb3v/8+uqWvqOd1JZ57nQAYgYQiDITgcEQQkoozy4x49hHOOF8/RK/4OKnoXeFW896dLXQ4XOMqgDIJB9BhIJIBMCQkZIQMZOul0eu6uqq5p7/37o0MllR7S3ZXd1cP7tVavldrPrl3ffjpV9aldz34ew7ZtWwAAAADOKFe+CwAAAACGI4I2AAAA4ACCNgAAAOAAgjYAAADgAII2AAAA4ACCNgAAAOAAgjYAAADgAII2gBFt8uTJ8vl8qq+vz9q+aNEiGYah/fv3S5Kqq6t17bXXatSoUSouLtb8+fP10EMPdXnM9evXa/z48Znbl156qfx+vw4dOpTZtnbtWk2ePDlz+5VXXtEFF1yg4uJilZWV6cILL9Rbb72l//k//6fC4bDC4bD8fr/cbnfm9rx58yRJhmEoFAopHA5r3Lhx+u///b/LNM2s33Ht2rVZNT700EO66KKLJEn79++XYRhatGhR1j719fXy+XxZdU6ePFmBQCBTQzgc1urVqzPHNAxD3/ve97KOM378eK1fv15f/OIXM/fx+Xzyer2Z2x//+Me77EsAGMoI2gBGvClTpuixxx7L3N66datisVjWPjfddJMmTJigAwcOqKGhQf/5n/+p0aNH9/oxQqGQ7rvvvi7bWltb9clPflJ33XWXGhsbdfjwYd17770qKCjQ17/+dUUiEUUiEf3sZz/T+eefn7m9ffv2zDG2bNmiSCSiv/3tb3riiSf061//uo+9IMViMW3bti1z+9FHH9WUKVM67ffHP/4xU0MkEtGPf/zjTFtZWZm+973vqa2trdP9fvazn2Xu8/Wvf12rVq3K3H7hhRf6XC8ADHYEbQAj3k033aRHHnkkc/vhhx/WzTffnLXPW2+9pVtvvVWhUEgej0eLFi3q01nYf/7nf9Zjjz2mvXv3dmp7//33JUk33HCD3G63AoGArrjiCp111ll9/l2mT5+uCy+8UJs3b+7zfW+66SY9/PDDmduPPPJIp344nTlz5uj888/XD3/4wz4/PgAMNwRtACPesmXL1Nraqp07d8o0TT3++OO68cYbO+1z55136vHHH9fBgwf7/Bjjxo3THXfcoXvvvbdT28yZM+V2u3XLLbfohRdeUFNTU79/l127dmnDhg2aPn16n+9744036vHHH5dpmtqxY4cikYiWLl3a5+Pcd999+tGPfqTGxsY+3xcAhhOCNgDoxFntv/71r5ozZ47GjRuX1f773/9ey5cv13333acpU6Zo4cKFeuutt/r0GP/jf/wP/fGPf8wa8iFJRUVFeuWVV2QYhu644w5VVFToU5/6lGpra3t97MWLFysUCmnOnDm69NJL9U//9E99qk3qGEs9a9YsrV27Vo888ohuuummLve7+uqrVVJSkvn5xS9+kdW+cOFCrVy5Ug888ECfawCA4YSgDQDqCNqPPvqoHnrooS6HS5SWlur+++/X9u3bVVtbq4ULF+rqq6+Wbdu9foyKigqtXr1a//Ef/9Gpbc6cOXrooYdUXV2tbdu26ciRI/rXf/3XXh9706ZNikQieuKJJ/TGG28oGo1m2jwej1KpVNb+qVRKXq+303FuvvlmPfTQQ3rssce6Ddp/+MMf1NzcnPm54447Ou3z7W9/Wz/96U/79GEBAIYbgjYASJo0aZKmTJmiP/3pT7rmmmt63HfUqFH6yle+oiNHjvR5eMS//du/ad26ddq4cWO3+8yePVu33npr1oWJvWEYhq6//nqdf/75+va3v53ZPnHixMzsKR/64IMPNGnSpE7HuPbaa/X8889r6tSpmjhxYp8e/2SzZ8/WNddco+9+97v9PgYADHUEbQA47le/+pVeeuklhUKhTm1f/epXtW3bNqXTabW1temnP/2ppk+frvLy8j49RklJie6+++6sKfB27dqlH/zgB6qurpYkHTp0SI899piWLVvWr9/ja1/7mn7xi1/o6NGjkqRVq1bpRz/6kXbt2iXbtvX222/r17/+tT772c92um8oFNJLL72kX/7yl/167JPde++9+r//9/+qubk552MBwFBE0AaA46ZNm6Zzzjmny7ZYLKZPf/rTKikp0dSpU3XgwAE999xz/Xqcf/mXf5Hb7c7cLiws1BtvvKGlS5cqFApp2bJlmj9/vn7wgx/06/gLFizQxRdfrP/1v/6XJOmOO+7QbbfdpiuvvFLFxcW6+eab9d3vflcf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Gq1cuXLkz59++qlisZg2bdpkYypnOXLkiPr6+rR9+/aRpz4Ym9fr1bJly9Te3q4tW7aot7dX33333cgnA5gc51t+uNYVjnstnIofrClQJpPR0aNH1dnZKbfbrRUrVuiRRx7hJpSH9vZ2Xb58mb1lpygWi+mVV16RaZoyjF++brF582b2hh5HKpXSoUOH1N3drUAgoNbWVmY1RZxvM4dr3fRxr4VTUbQBAAAAC7DrCAAAAGABijYAAABgAYo2AAAAYAGKNgAAAGABijYAAABgAYo2AAAAYAGKNgAAAGABijYAAABgAYo2AAAAYAGKNgAAAGABijYAAABgAYo2AAAAYAGKNgAAAGABijYAAABgAYo2AAAAYAGKNgAAAGABijYAAABgAYo2AAAAYAGKNgAAAGABijYAAABgAYo2ADhQV1eXIpGITp48KUm6dOmSamtr9cknn9gbDAAwwpXL5XJ2hwAATN+bb76p/fv36/jx43riiSfU3Nysffv22R0LAPAzijYAONiWLVt05swZuVwuffnll/L5fHZHAgD8jKUjAOBgzz77rL799lu98MILlGwAKDE80QYAh0okErr33nvV0tKio0ePqrOzU5FIxO5YAICfUbQBwKF27dqlRCKhd999V88995xisZjee+89u2MBAH7G0hEAcKBDhw7po48+0uuvvy5Jevnll3Xy5Em9/fbbNicDANzAE20AAADAAjzRBgAAACxA0QYAAAAsQNEGAAAALEDRBgAAACxA0QYAAAAsQNEGAAAALEDRBgAAACxA0QYAAAAs8P8JT1+9k1jaFgAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "date_data = result_to_plot.loc[result_to_plot['variable']=='MS_instrument']\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y',color = 'value'), data = date_data)+geom_point(size =75, alpha = 0.8)+theme_bw()+scale_color_manual(values = ['brown','mediumaquamarine','orchid'])+ggtitle('MS INSTRUMENT')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAt4AAAIhCAYAAAB5UL2TAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdeXTU933v/9d3vrNIo10CJCHEvkqABXKwsYkNtR2HLXWKgxOnTfi1/dVJnfaozT89p7+2uSe9dXtu6tZN05vbnnNvmqaO6+AkTowTHDu2SS54YUdsEosMSEIb2kezfr+/P8YMyNIIiRHf0fJ8nJMT5vuZ+c47n2h56TOfxbBt2xYAAACAO8qV7gIAAACA6YDgDQAAADiA4A0AAAA4gOANAAAAOIDgDQAAADiA4A0AAAA4gOANAAAAOIDgDQCTxPz58/X6668Pud7T06OamhrNnTtX2dnZWrRokWpqatTe3p6GKgEAyRC8AWASC4fDeuihh3Ty5En9/Oc/V09Pjw4cOKCioiK999576S4PAHATd7oLAADcvu9+97u6dOmS3nzzTWVnZ0uSZs2apb/4i79Ic2UAgI9ixBsAJrHXX39dn/zkJxOhGwAwcRG8AWAS6+joUGlpabrLAACMAsEbACaxoqIiNTc3p7sMAMAoELwBYBJ7+OGHtXfvXvX396e7FADALRC8AWASiUQiCgaDif/8zu/8jsrLy7Vjxw6dOXNGlmWpo6NDf/M3f6NXX3013eUCAG5C8AaASWTLli3KzMxM/OfrX/+6Xn/9dS1fvlyPPPKIcnNztW7dOrW3t+uee+5Jd7kAgJsYtm3b6S4CAAAAmOoY8QYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8J5igsFgukuY9OjD1NB/qaMPU0P/pY4+TA39h2QI3lOMZVnpLmHSow9TQ/+ljj5MDf2XOvowNfQfkiF4AwAAAA4geAMAAAAOIHgDAAAADiB4AwAAAA4geAMAAAAOIHgDAAAADiB4AwAAAA4geAMAAAAOIHgDAAAADiB4AwAAAA4geAMAAAAOIHgDAAAADiB4AwAAAA5wp7sAABgr27bV1NSkQCCgvLw8zZo1K90lAQBwSwRvAJNKY2Oj9u3bp97e3sS1GTNm6Dd+4zeUn5+fxsoAABgZwRvApHHt2jXt3btX0Wh00PX29nbt2bNHjz/+uHw+35jv29/frzNnzqi9vV1er1eLFi1SeXm5DMMYr9IBACB4A5g8Tpw4MSR0X9ff36+6ujqtWrVqTPe8cuWKXnvttUH3ra+v17x58/TII4/I5WIpDABgfPAbBcCk0djYOGL7lStXxnS/cDis119/fdgw/8EHH+jo0aNjuh8AACMheAOYNG419WOso9Pnzp1TOBxO2n769GnZtj2mewIAkAzBG8CkMXfu3BHb582bN6b7dXV1jdje39+vSCQypnsCAJAMwRvApLF69eqkiyfz8/O1ePHiMd0vMzNzxHaPxyOPxzOmewIAkAzBG8CkkZOTo23btg3at9swDM2dO1dbt26V2z229eJLliwZcfrKrdoBABgLdjUBMKkUFRXpscceU2dnZ+IAnezs7Nu6V3Z2ttatW6d33313SFteXp6qq6tTLRcAgASCN4BJqaCgQAUFBSnf56677lJhYaFOnDgxaB/vVatWKSMjYxwqBQAgjuANYNorLy9XeXl5ussAAExxzPEGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcQPAGAAAAHEDwBgAAABxA8AYAAAAcYNi2bae7iIkuGAzKsqx0lzEqsVhMpmmmu4xJjT5MDf2XOvowNfRf6ujD1KSj//x+v6Pvh9tD8J5iAoEA33wpog9TQ/+ljj5MDf2XOvowNfQfkmGqCQAAAOAAgjcAAADgAII3AAAA4ACCNwAAAOAAgjcAAADgAII3AAAA4ACCNwAAAOAAgjcAAADgAII3AAAA4ACCNwAAAOAAgjcAAADgAII3AAAA4ACCNwAAAOAAgjcAAADgAII3AAAA4ACCNwAAAOAAgjcAAADgAII3AAAA4ACCNwAAAOAAgjcAAADgAII3AAAA4ACCNwAAAOAAgjcAAADgAII3AAAA4ACCNwAAAOAAgjcAAADgAII3AAAA4ACCNwAAAOAAgjcAAADgAII3AAAA4ACCNwAAAOAAgjcAAADgAII3AAAA4ACCNwAAAOAAd7oLAIA7KRKJqKmpSZZlqaSkRJmZmekuCQAwTRG8AUxZR44c0dGjRxWJRCRJpmlq2bJluu++++Ry8YEfAMBZBG8AU9KxY8f0/vvvD7oWi8V06tQp2batj3/842mqDAAwXTHkA2DKicViOn78eNL2s2fPqr+/38GKAAAgeAOYgtrb2zUwMJC03bIsNTY2OlgRAAAEbwBTkGEY4/IcAADGE8EbwJQzY8YM+f3+pO0ul0tz5sxxsCIAAKZ58O7o6NDXv/51vfTSS+kuBcA4crlcqqqqStq+YsUKthUEADhuWu9qsmfPHpWVlaW7DAB3wMqVK2Xbto4cOaJgMChJ8ng8qqio0Lp169JcHQBgOpq2wfvEiRPKyMjQzJkzde3atcT1np4e9fX1DXpudna2cnNznS7xtjBvNXX0YWomUv+tWrVKFRUVunr1qizLUnFxsbxeb7rLuqWJ1IeTEf2XOvowNfQfkpmWwTsYDOrNN9/UF7/4RR0+fHhQ26FDh/T2228Puvbggw9q06ZNTpZ42/j4PHX0YWomWv+ZpjnpPtmaaH042dB/qaMPU0P/IZlpGbzffPNNrV27Vnl5eUPaqqurtWzZskHXsrOznSotZQMDA3zDp4g+TA39lzr6MDX0X+row9TQf0hm2gXv5uZmXbhwQU899dSw7bm5uZNmWslwbNtOdwmTHn2YGvovdfRhaui/1NGHqaH/kMy0C94NDQ3q6urSP/zDP0iSwuGwbNvWt7/9bX3pS19Kc3UAAACYqqZd8K6urtbKlSsTj/fv36+uri5t27YtjVUBAABgqpt2wdvr9Q7a1cDr9crtdisrKyuNVQEAAGCqm3bB+6Mmy24lAAAAmNym9cmVAAAAgFMI3gAAAIADCN4AAACAAwjeAAAAgAMI3gAAAIADCN4AAACAAwjeAAAAgAMI3gAAAIADCN4AAACAAwjeAAAAgAMI3gAAAIADCN4AAACAAwjeAAAAgAMI3gAAAIADCN4AAACAAwjeAAAAgAMI3gAAAIADCN4AAACAAwjeAAAAgAMI3gAAAIADCN4AMIWEQiG1tLSou7s73aUAAD7Cne4CAACpi0QiOnDggOrr6xWLxSRJM2fO1Pr161VSUpLm6gAAEiPeADDp2batvXv36syZM4nQLUltbW169dVX1d7ensbqAADXEbwBYJJrampSU1PTsG3RaFRHjhy5rfu2trbqxIkTOn36tAYGBlIpEQAgppoAwKTX0NAwYvsHH3wg27ZlGMao7jcwMKDXXntNLS0tiWv79+9XVVWVqqurUykVAKY1RrwBYJKzLGvEdtu2x3S/vXv3DgrdkhSLxXTo0CGdPn16zPUBAOII3gAwyc2ePXvE9pKSklGPdjc1Nam1tTVp+7Fjx8Yc5AEAcQRvAJjkFixYoLy8vGHbDMNQVVXVqO/V3Nw8YntPT48CgcCY6gMAxBG8AWCSc7lc2rp1q2bNmjXous/n0wMPPKDy8vJR38s0zVG9HwBg7FhcCQBTQHZ2th577DG1traqo6NDXq9X8+bNk9s9th/zCxYs0Pvvv590OklJSYkyMzPHo2QAmHYI3gAwhcyaNWvIyPdY5OXlaenSpTp79uyQNpfLpY997GOplAcA0xrBGwAwyAMPPKCsrCydOnVKwWBQUvwUzHXr1qm0tDTN1QHA5EXwBgAMYhiG7r77bq1Zs0bd3d3yeDzKyclJd1kAMOkRvAEAwzJNU4WFhekuAwCmDJamAwAAAA4geAMAAAAOIHgDAAAADiB4AwAAAA4geAMAAAAOMOxkx5MhIRgMyrKsdJcxKrFYbFRHPiM5+jA19F/q6MPU0H+pow9Tk47+8/v9jr4fbg/Be4oJBAJ886WIPkzNdOm/zs5OXbhwQbFYTCUlJSovL5dhGONy7+nSh3cK/Zc6+jA19B+SYR9vABgD27a1b9++IUeqFxQUaPPmzcrOzk5TZdNXW6hPR7sadS0cULbbp2W+Qi0m9ACYgAjeADAGhw8fHhK6pfgI+N69e7Vjx440VDV9Heq8rNdazurmyYCHrSu6N9KjR4qXpq0uABgOiysBYJRisZhOnTqVtL2jo0NNTU0OVjS9tQb7tPcjofu69zov6Uxvq+M1AcBICN4AMEp9fX0aGBgY8TmtrYQ9pxzuuqKRFikd7rziWC0AMBoEbwAYJbf71rPzPB6PA5VAkq6FAyO2d4T7HaoEAEaH4A0Ao5SVlaWSkpKk7S6XSwsXLnSwoukty+0dsT3b7XOoEgAYHYI3AIzBPffck3Tku6qqSpmZmQ5XNH2tzisdsX3VLdoBwGkEbwAYg+LiYm3fvn3Qvt35+fl64IEHdPfdd6e5uullQVaR7sqbPWzbfH+BqvLKHK4IAEbGATpTDJv2p44+TM106r9IJKJYLKaMjIxxve906sNU2bat2p6rOtx1RdfCAeW4fVqeWaR7Zy2S28XY0u3iazA19B+SYR9vALhNHo+HxZRpZhiGVuWVDppWEggECN0AJiR+MgEAAAAOIHgDAAAADiB4AwAAAA5gjjcAIG06wwE1B3vkdbk131/I3GwAUxrBGwDguIFYRK80n1J9X1vi2He/6dGmmYtVlc82gACmJoYWAACO233lmOpuCt2SFIhFtOfqaZ3tbU1bXQBwJxG8AQCOuhTo1KWBrqTt/7fjooPVAIBzCN4AAEdd6O8Ysb052KuBWMShagDAOQRvAICjDBnpLgEA0oLgDQBw1JLsGSO2l2fmKdPkRFAAUw/BGwDgqNmZeVqcVTRsm0vShhkLnS0IABxC8AYAOO63ylbrrrzZMo0b007yPRn6dNlqLUwSygFgsmMfbwCA4zwuU9tKK7Rp5mK1hnrldblVmpErl8H8bwBTF8EbAJA2WW6vFrgZ4QYwPTDVBAAAAHAAwRsAAABwAMEbAAAAcADBGwAAAHAAwRsAAABwAMEbAAAAcADBGwAAAHAAwRsAAABwAMEbAAAA0052drbj70nwBgAAABxA8AYAAMCk92d/9mf61re+lXj8ta99TX/913+thx56SGvXrtWqVav08ssvD3ndW2+9pW3btiUef+UrX9F3vvMdSdKhQ4f04IMPqrq6Wo8++qiam5tTqpHgDQAAgEnviSee0Isvvph4/OKLL+qLX/yifvSjH+nw4cN688039dWvflW2bY/qfpFIRH/0R3+k3bt369ChQ/rd3/1d/fmf/3lKNbpTejUAAAAwAaxZs0atra1qampSW1ubCgoKVFJSoj/5kz/Rvn375HK51NjYqJaWFpWUlNzyfmfPnlVtba0eeeQRSVIsFlNpaWlKNRK8AQAAMCV85jOf0e7du3X16lU98cQT+s///E+1tbXp0KFD8ng8mj9/voLB4KDXuN1uWZaVeHy93bZtVVZW6sCBA+NWH1NNAAAAMCU88cQTeuGFF7R792595jOfUXd3t2bNmiWPx6M333xTH3zwwZDXzJs3T6dOnVIoFFJXV5feeOMNSdKyZcvU1taWCN6RSEQnT55MqT5GvAEAADAlVFZWqre3V2VlZSotLdXnP/95bd++XatWrdLdd9+t5cuXD3lNeXm5du7cqZUrV2rBggVas2aNJMnr9Wr37t364z/+Y3V3dysajaqmpkaVlZW3XZ9hj3aGOSaFQCAgv9+f7jImNfowNfRf6ujD1NB/qaMPU0P/IZlpN+IdjUa1Z88eXbhwQQMDAyooKNDDDz+sJUuWpLs0AAAATGHTLnhblqXc3Fzt2rVLeXl5qq+v1w9+8AN9+ctfVkFBQbrLAwAAwBQ17YK31+vVpk2bEo+XLVum/Px8NTc3q6CgQD09Perr6xv0muzsbOXm5jpd6m0xDCPdJUx69GFq6L/U0Yepof9SRx+mhv5DMtMueH9UX1+fOjo6NHPmTEnxE4refvvtQc958MEHB4X1iSwzMzPdJUx69GFq6L/U0Yepof9SRx+mhv5DMtN6cWUsFtP3vvc9FRYWavv27ZI06Ue8BwYG+IZPEX2YGvovdfRhaui/1NGHqaH/kMy0HfG2LEs//OEPZZqmtmzZkriem5s7aUL2cKbx31Hjhj5MDf2XOvowNfRf6ujD1NB/SGZaHqBj27Z+8pOfqL+/X0888YRM00x3SQAAALgDdu3apd27dw+5XldXpy1btmjJkiVau3atdu7cqZaWFknSM888o8WLF2vZsmXau3fvuNUyLUe8X3nlFbW1tekLX/iCPB5PussBAACAg4LBoLZu3apnn302Md34rbfeUltbmzo6OvTCCy/o5MmTampq0sMPP6y6urpxGaiddsG7q6tLhw4dkmma+sY3vpG4vn37dq1evTqNlQEAAExu/+2//bc7/h5/9Vd/Nez1hoYGbd68WRs2bND+/ftVVlaml19+edjnPv/881q/fn0idEvSxo0bJcVHuz/72c/K5/NpwYIFWrx4sd577z2tX78+5dqnXfDOz8/X1772tXSXAQAAgHFWX1+v73//+/q3f/s37dy5Uy+99NKwz6utrVV1dfWwbY2Njbr33nsTj+fMmaPGxsZxqW9azvEGAADA1LNgwQJVVVVJkqqrq9XQ0JDegj6C4A0AAIApwefzJf5tmqai0eiwz6usrNShQ4eGbSsrK9Ply5cTj69cuaKysrJxqY/gDQAAgGnlySef1P79+7Vnz57EtX379qm2tlaf+tSn9MILLygUCunixYuqr6/XunXrxuV9p90cbwAAANwZyRY+pttTTz2lmpoaSVJ5ebkOHDigV155RTU1NaqpqZHH49Hq1av13HPPqbi4WDt37lRFRYXcbre+9a1vjdvW09P65MqpKBAIyO/3p7uMSY0+TA39lzr6MDX0X+row9TQf0iGqSYAAACAAwjeAAAAgAMI3gAAAIADCN4AAACAAwjeAAAAgAMI3gAAAIADCN4AAACYsnbt2qXdu3cPuV5XV6ctW7ZoyZIlWrt2rXbu3KmWlhZJ0jPPPKPFixdr2bJl2rt3ryTp8uXL2rRpkyoqKlRZWannnntuzLVwgA4AYNqwbVsnepp1pKtR18IB5bh9uitvttYWzJFpMBYFTBfBYFBbt27Vs88+q+3bt0uS3nrrLbW1tamjo0MvvPCCTp48qaamJj388MOqq6uT2+3W3//932vt2rXq7e1VdXW1HnnkEVVUVIz6fQneAIBp45Wrp3S8uznxOBCL6LXWOtX3teuJ8irCN5Ci5ysr7/h7PHny5LDXGxoatHnzZm3YsEH79+9XWVmZXn755WGf+/zzz2v9+vWJ0C1JGzdulBQf7f7sZz8rn8+nBQsWaPHixXrvvfe0fv16lZaWSpJycnK0YsUKNTY2jil48xMGADAtnO/rGBS6b3YxcE1Hu5ocrgjAeKuvr9fTTz+tkydPKj8/Xy+99NKwz6utrVV1dfWwbY2NjSovL088njNnjhobGwc9p6GhQUeOHNE999wzpvoI3gCAaeFE98jB+vgt2gFMfAsWLFBVVZUkqbq6Wg0NDeP+Hn19fdqxY4f+8R//Ubm5uWN6LcEbADAt9MfCI7dHR24HMPH5fL7Ev03TVDQaHfZ5lZWVOnTo0LBtZWVlunz5cuLxlStXVFZWJkmKRCLasWOHPv/5z+u3fuu3xlwfwRsAMC0Uev0ptQOYOp588knt379fe/bsSVzbt2+famtr9alPfUovvPCCQqGQLl68qPr6eq1bt062bev3fu/3tGLFCv3pn/7pbb0viysBANPC2vw5OtLVKDtJe3XBHEfrwdRk27Ysy0p3GWmTbOFjuj311FOqqamRJJWXl+vAgQN65ZVXVFNTo5qaGnk8Hq1evVrPPfeciouLtXPnTlVUVMjtdutb3/qWTNPUr3/9a/3Hf/yHVq1alZjO8jd/8zfasmXLqOswbNtO9jMIk1AgEJDfz6hNKujD1NB/qaMPUzNS/x3svKzXWs4OCd/3FM7Vw7OW3vniJgnHvwZjYam7Nv7vvErJ9I38/Amop6dHhw8f1oULFxQOhzVz5kytXLlSy5YtS3dpmEAY8QYATBt3F5Rrnr9AR7sadS08EN/HO3+2yjLz0l3a9HXxP6QL35Ei3fHHnlxp/m9LC/8fyTDSWtpodXd36yc/+YkGBgYS1zo6OvT222+ru7tb69atS2N1mEgI3gCAaWWmL1uPFDMKOSFc+Hep7puDr0V6pPp/keyotPgP0lPXGB08eHBQ6L7ZsWPHtGLFCuXk5DhcFSYiFlcCAEbFiliyQtN37irGWSwYH+lO5uL3pGjAsXJuVywWG3HLOtu2de7cOecKwoTGiDcAYEShpqC6D3Qp+MGAZEveYq9yP5Yv/7KsdJeGyazzmBTtTd4eC0jXDkqzHnCuptsQjUYVi8WGXLcsS+FwfIvKnp4ep8vCBEXwBgAkFbw0oLYftsiO3ViOGG4Jq/2VVhUEipSzZmyHRwAJ9tCwOvQ5E/8TFq/Xq5ycHPX23vgjor+/X6FQKPH4+PHjsixLDzzwgEzTTEeZmCCYagIASKrr7WuDQvegtl9fkxWe+MEIE1TBXZKZmbzd5ZUK1zpXz20yDEMVFRWJx319fQoGg4nHLpdLXq9X9fX12r9/fzpKxARC8AYADCtyLaxwa/LTHO2wrYELE38OLiYod5Y094nk7eU74jucTAKrV6/W0qVLZdv2oNBtGIZyc3NlfLg7S11dXdJFmLhzdu3apd27dw+5XldXpy1btmjJkiVau3atdu7cqZaWFnV0dGjTpk3Kzs7WV77ylUGv+eQnP6m77rpLlZWV+tKXvjTsNKORELwB4A6zrcl5XIIVvnXdLLZESpb+YXzrQJf3xjWXV5r3WWlZTfrqGiPDMLRx40bdf//9yszMVEZGhrKzs1VYWCi3+8as3lgspqtXr6axUlwXDAa1detWffnLX1Z9fb0OHz6sP/zDP1RbW5syMjL09a9/Xd/4xjeGvO7FF1/UsWPHVFtbq7a2Nv3gBz8Y0/syxxsA7oBoV0Td73YpcLZfdsSWt9irnOo8Za3ITndpo+Yp8MjwGLIjyQO4t3jyHXSCCcRwSctr4nt2d7wnyZaKPiZ5C9Jd2W0pKChQVlaWLMuSyzX82OaUn+P9vAN7rz85/M+khoYGbd68WRs2bND+/ftVVlaml19+edjnPv/881q/fr22b9+euLZx48bEvzds2DDsbjS5ufFPYaLRqMLhcOLTjNEa9Yj3n/zJn+jo0aNjujkATEeRzoiufr9Z/bV9idAabgmr49U2de/vTHN1o+fyuZS9Kvnew74yn3wlBG+MA2+eVPqIVPqJSRu6JamkpEQZGRlJ230+n2bPnu1gRdNPfX29nn76aZ08eVL5+fl66aWXhn1ebW2tqqurb+s9Hn30Uc2aNUs5OTl6/PHHx/TaUQfvWCymRx99VCtXrtTf/d3f6cqVK2MuFACmg+5fd8oKDD/vr/vdLkV7ow5XdPvyP16ozMVDjw73zPKqaNusNFQETFymaY4Y5qqqqgZNPcH4W7BggaqqqiRJ1dXVI+6xfrv27t2r5uZmhUIh/fKXvxzTa0cdvP/pn/5JTU1N+tu//VsdPXpUK1as0MMPP6zvfve76uvrG3PRADAVWWFLA+f7R3iCFDgzeX5mGm5DM3+zWMWfn63ce/KUc3eeZn66WCWfny13NgEC+KjKykrde++9ys6+Ma0sKytL999/v+666640VjY9+Hw3PoUzTVPR6PADHZWVlTp06NBtv09GRoZ+8zd/M+lUlmTGtLjSNE1t27ZN3//+9/XOO++ora1Nu3btUklJiX7/939fjY2NY3pzAJhq7Ih1y+2JreDkW5DoK/Epf0OhCh4sVOZCvwyXA/M4gUlq6dKl+tznPqcdO3Zox44devLJJ1VZWZnusnCTJ598Uvv379eePXsS1/bt26fa2tqkr+nr61Nzc7Ok+BzvPXv2aPny5WN63zENV/T09OgHP/iBvve97+n48ePasWOH/uVf/kVz587V3//932vz5s06fvz4mAoAgKnElWnKzDYV60uevj0zvUnbAEwNhmGoqKgo3WU4L8nCx3R76qmnVFMT3ymnvLxcBw4c0CuvvKKamhrV1NTI4/Fo9erVeu655yRJ8+fPV09Pj8LhsH784x/rtddeU1FRkT71qU8pFArJsixt2rRJX/rSl8ZUh2Hb9qh66PHHH9fevXv1wAMP6Atf+IIee+yxQcP5lmUpLy9v0MlNcF4gEJDfP3Q+JkaPPkwN/Refx9396+EXUZo5pmb/XrkMM/mIMX2YGvovdfRhaug/JDPqEe97771X//zP/6ySkpJh210ul1paWsatMACYrHI/lqdIe1iBM4Pnept+UzMfKx4xdAMApq5Rj3hjcuCv7NTRh6mh/24INYcUONsnO2zLW+qTf3mWXJ5bL62hD1ND/6WOPkwN/YdkWJIOAHeIr9QnXyn7XAMA4gjewDR3+fJlnTp1Sj09PfL7/Vq+fLkWLlw45tO4AADAyAjewDT27rvv6tixY4nHnZ2damxs1MWLF/XQQw8RvgEAGEfM8R6FYDAoy2tb3MUAACAASURBVJoc++7GYjGZppnuMia16dKHLS0t2rt3b9L2+++/X4sWLRrzfadL/91J9GFqbrf/Yn0xWb0xubJcMnOn97jUnfwajLSEFboQlB2TvLO98s73Tbl94dPxPcyc8slhev9kGaWMjIx0lzBqLOgYhm1LVlgyRzfXdiL34cDAgM6dO6dAIKD8/HwtWrToto8f/uCDD+RyJV/od+HCBa1atWrM953I/TdZ0IepGWv/RXuj6nyjQwMXA9KHYywZczNU8NAMeQo9d6jKie1OfA3aUVvtr7ZqoD6QuBY6MSBPkUczd5TInTMxI4kVjn9RuLyjP3OQ7+GJZdeuXdq2bZsef/zxQdfr6upUU1Oj+vp65eTkaPHixfrmN78pt9utxx9/XO+//7527dqlf/7nfx5yz0996lO6cOHCiAfuDGdifpUD4yF0TTr/b1LjHikWkDJnS+WPSwt+WzLGdGjrhHDy5Em98847isVuHMzyzjvv6JFHHtHs2bPHfL++vpGPLe/vH+HYc2CKsMKWWn/QrGjn4GOlg5eCav2vZpX8zmyZ2fyqHA9dv742KHRfF+mIqP0nrSr5/Nh/jqXMtpL+PhhoCKjnnS6FGkOSJN+cDOXdm6+MeZlOVog7JBgMauvWrXr22We1fft2SdJbb72ltrY2LViwQF//+tdVW1s7bLD+4Q9/qOzs7Nt6X36aYGoKd0nv/p4UuHzj2kCTVPdPUs9pqeqZ9NV2GxobG7V//359dGZYKBTS3r179cQTT4x5dCUnJyeldmAq6D/ZNyR0XxcLxNR7tEf5GwodrmrqscKW+k4kP2AvfDWkUFNQvtkOfMIcC0kX/126/GMp1Cr5Zknlj0kLvpj4ZLT/TJ86ftaW+AREkkJXgmr94VXN2DpL/qVZd77OSeqpwz+44+/xv9Z+ZtjrDQ0N2rx5szZs2KD9+/errKxML7/88rDPff7557V+/fpE6JakjRs3Jv69YcMGnTt3bsjr+vr69Oyzz+pf//VftXPnzjHXPvmG/YDRuPi9waH7Zld/IV075Gw9KTpx4sSQ0H1dJBLR6dOnx3zP5cuXp9QOTAUD50f+ZGfg3NARWoxdtCsiOzzykrJwS/jOF2JFpIN/JJ3713joluL/fe5f49etiGzLVtfb1waF7huvlzrf6pBtsTxuoqqvr9fTTz+tkydPKj8/Xy+99NKwz6utrVV1dfWY7/8Xf/EX+upXv3rbU4kI3piaml4dub3xFu0TTFtbW0rtwykuLk76Q2fJkiVavHjxmO8JTDZ27Bbtk2Nd/YQ3mvnRLq8DCyybfiZ1Hh6+rfOw1PQzha4EFetL/oUR640p1Bi8QwUiVQsWLFBVVZUkqbq6Wg0NDeN276NHj+r8+fP69Kc/fdv3YKoJpqboyPOXFU3+kedE5PF4NDAwMGL77aiurtbs2bMH7eO9bNkyzZs3j60EMS1kzMtQ6EryEJUxd/Isrp/I3PkeeUt8Cl8NDdtueAxlLnZg+satBmWafiar8KFb3uZWo/dIH5/vxkYKpmkm/d1ZWVmpt99+e0z3PnDggA4ePKj58+crGo2qtbVVGzdu1FtvvTXqexC8MTXlLk8+qnG9fRJZtGiRjhw5MmL7SMLhsI4fP666ujoNDAwoPz9fFRUVWr58uUpLS1VaWjreJQOTQvaqXPUe7pE1MHRo2/AYylmbl4aqpqaCjYVq3X1VdnRoaM3fUCCXz4EP4SM9t2jvlnemNz4fINmnHS7JM8s73pXBYU8++aSeeeYZ7dmzR1u3bpUk7du3T4WFhVq5cuWwr/nyl7+sL3/5y5Li88m3bds2ptAtEbwxVc3/XPLgbWZKcx5ztp4UrVy5UufOnVNv79CR+rKyMs2bNy/payORiF555RW1t7cnrnV0dOhXv/qVrl69qk2bNt2RmoHJwMwyNWtHidr3tCnaGblxPcdU0SdnTtvtBO8EX1mGZj1Rqp4DXRpoiG/d6C32Kvdj+fIvc2ixYs5SqbduxHZ3nkf+RX4FhtmBRZL8S7Im7NaHE0GyhY/p9tRTT6mmpkaSVF5ergMHDuiVV15RTU2Nampq5PF4tHr1aj333HOSpPnz56unp0fhcFg//vGP9dprr6mioiLlOjhAJ82CwaDq6urU3d0tv9+vpUuXprSbBHuH3uTcv0rn/k3STV/ipl9a8z+kGfckfdlE7cP+/n4dPHhQ58+fVzQaVUZGhpYvX67q6uoRD2o4cuSI3n///aTt27Ztu63tCG9m27ZCoZDcbrfC4fAt+8+ybR3puqIjXY3qiQSV68nQmvwyrcmfIxdTXCbs1+BkcTv9Z9u2QpeDinZHZWabypiXOeUOdRmLO/01aEdt2ZY9pr2xx0X3KenALg0/nO2S1n9HyquQFYyp7eXWIdOQfHMyNPOx4luOzvM9jGQI3ml08eJFvfnmm4pGb2xlZRiG1q1bp7vuuuu27sk3+0cErsTn9IU7pawF0uwtkmfkvTcneh/GYjGFw2H5fL4RD8C57sUXX1RXV1fS9qVLlw7aQmksbNvWsWPHdPLkSfX398s0TZWVlem+++5Tbm7usK+xbFu7G4+pvq99SNvS7JnaUbZ62ofvif41ONHRf6mb0n14+UfSqb8dvLLWMKWKP5PKBy+aC14aULAhPkc4Y0GmMspHt4f3lO4/pITPStKkt7dXv/zlLwcdhiLFg8y7776roqIizZkzJ03VTSH+OdLiP0h3FePKNE3J69aZvlbZkub5C5TtTn4qZzA48ur7W7WP5K233lJ9fX3icSwWU0NDgwIN/dqwcoP8+X75F/vlyrgxIn+6t2XY0C1JdX1tOtPboorcktuuaaqzbVsffPBBYr5+QUGBKioqNGPGjHSXBkwO5Z+WZt4vNf5UCjRJ/tlS2XYpY9aQp2bMzVTGXA7MwfgheKfJqVOnhoTum9XW1hK8J7D2rqhOXQzLtqWKhV7NzHfmW8mybb3Vdk7vd15W9MN9zkwZWp0/W48WL5M5zAlsBQUFam5uTnrPwsKxHw5i27aONJ7Xu+0Ncue4ld0XlcuWvBGvFrUskD+SqbaWFuVk56jzl4byNxQkFqkd724a8d7HupsJ3knYtq033nhDFy5cSFxraWnR2bNndd9996mysjKN1WEiCV0Nqb+2V7HemNz5bmWtypF3BgsCEzJmSYt+L91VYBoieKfJzQvdhtPR0eFQJRiLaMzWf/68R+/UDuj6JC1D0rrKDP325jx53Hd2isSv2y/owLUPEo9jtqX+WES/ar+gtkCPqnozNDAwoLy8PC1evFgej0eVlZVJg7fL5dKKFSvGVENbqE8/bDyuD661aqAkvtWaGbNV2hTU+tOL5Iv4JCN+qmZOdo7siK3ON68pYA/oYqRBF41WDXikjIwMGcNMlemPDr/dGKTTp08PCt3X2badOKUtPz8/DZVhIun69TX1vNs96FrvkR7lP1io3Gp2aQHSieCdJjfvMzkcr5eRiYlo9xu9OnBi8J6gtqR3Twbl9Rj6/Cfv3C+1sBXT+503TuPsjQTVH4uf9GZZlt4Z+EAneyKaeykgb8TWe++9p4ceekgLFy7UXXfdpWPHjg26n2ma2rhx45gW8wZjUf3npcMyrsW06nShsjtNhd0xXSrpkdy58loZur6Y9eblI339fWr46Qc6M7tOobIM9ed6FAgElJubK89HvtaLvBPjKGbbshVuDsmK2PIWe2VmJl/A6pQzZ84kbbNtW2fOnNG9997rYEWYaAYuBoaEbkmSLXW9fU2+sgz5Skb+/QPgziF4p8mSJUuGHbm6uR0TS9+ApV8fS3589IETA9r+8WzlZt2ZgNY00K2gFV+IG4iGE6HbtmxZsfi0k2Cmqcvlfi280K9QKKTXXntNTzzxhO655x4tXrxYdXV1CgQCys/P1/Lly5WVNbaQe7y7STkXDVUeLJRtWYn3LbmWJcuwFXVJnlg8cHvc8R8voVBQAwMDypJfhm2ooDOinlyPbNtWT0+PCgsLB418Vxfc2SlWkUhEJ06cGDJHeunSpYnn9J/pU9e+a4r1xqeDGW5DWRXZKthUJOMOf6oxkp6ekfcgvlU7pr6+oyMcDmZLfcd75CuZ6VxBAAbhyPg0mTt3rubOnTtsW2Fh4bjsFYnxdbExrOgIx0tHY9KFxkjyJ6QosdOHrUToluKj3Qm2FPa51JcdD73RaFSnT5+WJBUVFWn9+vV66KGHVF1dPerQfX0O8aVLl3Sl/ZoqD+XKsCWX4YrPs/lQVtAjb+zG3/KZmfEFSTdODbNly5Y/ENPM1vh0Etu2By3u3Dhzkeb6C0ZV1+2IRCL66U9/qoMHD6qnp0eRSEStra1666239Ktf/UqSFDjXr45X2xKhW4pvfdZ3vFcdr7besdpG41b/n431DylMPZHOkX8GRTvu3M8oYKLatWuXdu/ePeR6XV2dtmzZoiVLlmjt2rXauXOnWlpa1NDQoMzMTFVVVamqqkpf+tKXxq0WRrzTxDAMfeITn9CxY8d0+vRp9fX1yefzaenSpVq7di1TTSYg9yhGOt3mnRsNnZ2RpyzTo95oSDH7Rti2b9qn3GXF/z2QaSqnLz463tp6e2Gxu7tbb7zxxqD1CH73PClWLH34R4BpmvFFwrYUcceUPeBV0B3fx9vny1A0GlU4EpEhQ93+XpV1zlZRX4HMBlO9mUHVl3eqb6mhlWXlqsqbreKM29/DfjROnDiRdH3F6dOntXTpUlkHooO2fr9ZoD6gcFs4frJdGixbtkzvvPNO0vblyyfXiawYf6bfpWjnCO136BM5YLIJBoPaunWrnn32WW3fvl1SfKeutrY2ZWdna9GiRTp69Oi4vy/BO41cLpfWrFmjNWvWKBaLjXgICtJv8Ryvcvwu9QaGP0fYn2Fo6dw7F8jcLpfuK1qg11rODttuRq3EAPT1AC7d3nqBSCSiPXv2qK+vb9D1nE4lvlYNw5AhQ27TLdu2ZLkkRaT8vDzJMNTZ1aloNCorZimmmHz9XuUFchOj5HkBv+4+65dcLlXft2zMNd6Om7c+HM654/Uqby0b8TkDFwJpC96VlZW6fPmyGhsbh7StXbtWRUVFaagKE0lWZY5CjckXKGdV3tk/boHf+MNLd/w9fvkvw88YaGho0ObNm7Vhw4bEgvOXX3552Oc+//zzWr9+fSJ0S0qcadHQ0DDeJScw1WSCIHRPfB63oa33J/8of+v92fJ67uz833WFc/Vo8TJlmfHgZ9u2DBlyRWIyo7YKenxadCVPCxuzZVrxb+9FixaN+X3q6+uHhG5JMmJBuSxblj34jw/DcMltmsqakyV3pVedvZ2Jg6F6fL3q8FyT23IPu4VmQXPuLT8eHy83pr0kaU9hT3MnmKapT37yk/r4xz+u4uJi5eXlad68edq8ebPuvvvudJeHCSCrIlsZ84ffd9q/PEsZC9mTGlNbfX29nn76aZ08eVL5+fl66aWXhn1ebW2tqqurk97n4sWLWrNmjR588MHEVMTxwIg3MBpWTIr2aeOaLLlNQz870K+O7niILMx16ZPrs/XAGmdOKftY4VwVunz6n2d+pUgsIrcleQak+06WaVaPX2ZM8kQsWcYcDSwMaf78+WN+j+FGVCWpI/uaZneVKiZDhk+JLRV9LlO5ngzl35WnQ6EjujjngrxRn2KumMKusFZfiO8vbSt+TPT1o7gzMjLkdnsUON2nvPvu3Nzu6woKCtTS0pK0Pa8kT54OjyIjzIPNTBJqnGKaplasWDHmbSAxPRimoZmPFavveK/6ansV643KnedR9uocZVVmy5jmp8Ji6luwYIGqqqokSdXV1bc1el1aWqpLly6pqKhIhw4d0mOPPaaTJ08mPZF5LAjemNKiPVGFGoMy3IYy5mXK5R3jhzzRAen8v0lXXpYi3ZI7Sxtmb9V9v/uUmnv8ki2VznDL5XL2l1nt2++ovLtLbbN86ve79WDtXBV0++SKxOSOSS63KX+GX7O6Zylwul9ZFdljun+yo+gj7oguF17R/M65KsjNUcy25JIh03DJW+pT7rp8Nb7QKMtlK+iNjx67bJe8Lq8s25JlWbJtSx7Tp4zMDGVmxENsLDDCqtVxVFFRkTR4u1wuVc7skF34pjoaqiSXW/LkSd4CXZ8fEyyTfmGdl5qlBVlFWpYzc9hDi4B0MkxDOWtylbMm9ZAATDY3b9dsmmbSTzorKyv19ttvJ73H9ftUV1dr0aJFqqurG5dPFgnemJKsiKXOX7Sr/2y/9OGsCMNrKO+efOWuG+UBI1ZEOvRHUudNiyui/dKlF+W6dlhl9/5vye3MKPfNmpub1dLSokxJcy8NKCuUo5J2jwzbkmTIdJsqKCyQ8WFY7Hm/a9jgbdm2zva26kRPs/qjYc3wZmltwRwVR7M0t3uOvE2mbNnq8nerLadDMTMejtty21WyvETZrmxFWsNy+Vzyr8hW1spsBcNBRSKR+BSYD0fWbMNW2BOWN+qVy+WSz+tVbu7g/c49RaOfM93S0qKLFy8qFouptLRU8+fPT/qHwkctWbJEra2tOnny5KDrLpdLv7niivxnvi15JWv+RXVfflhWcECK9MjKmqsLxb16r7JDse74MP/R7ibN9Gbpc+VrleNhX2QAmEyefPJJPfPMM9qzZ4+2bt0qSdq3b58KCwtVXFyswsJCmaapCxcuqL6+XgsXLhyX9yV4Y0q69vN2Ber6B12zw7a6ftUpw+Ma3UhQ8y8Gh+6b9Z2TLv9QWvDb41Dt8CJWTAc7L+t4d7P6oyEVerNUXTBHkY+cQpnfny3jpl04YlZMtmXJcMXXDUTaI4oNxAYdAGPZtn7UeEJn+m7seNIU7FFDQ5s2vVMssy+mjIEM2Zat0oFMzegpUl3pOYU9EXm9XlV8vFJ5eTfCc3d3t/b+Yq+uXLmi7u5uhcNh+Xw+ZWfHP9q+ltWpuR3lclumzJipqBWRy2/K5XXJ8BqjGpGPxWJ64403Bn1sePLkSeXl5WnLli2jPgjo/vvv15IlSxL7eOfn56ui3K2so99OPCen5H1lzzqsYPciWTGvXl+2WbU5QxcutoX79ZPmWn1+bvJ5ggAwnSRb+JhuTz31lGpqaiRJ5eXlOnDggF555RXV1NSopqZGHo9Hq1ev1nPPPad9+/bpL//yL+XxeORyufTtb39bhYWF41KHYd98vBwmvUAgIL/f+VHYiSRyLaLm/3MlabuZY2r275cn5hl/VKIPD/6x1L4/+RvlrpDu+49Uyx1WxIrp+cuHdWVg6Al0JQMuxd4/l3hc2lmi2V0lg55TVFQU32f7Q3O+Mk8u343Hhzuv6GctHzkF0Zbu+3mBvD2SL2TJsG1ZsZisD39E9GX1q29NQPfdd59mzrxxAEd/f79+9KMfKRCIHy4UDocTB7m43W6V+Iu1rHmJskJ+uS23TJcZ367PkNwFHpX+dpky5t163vTrr7+uU6dOyeVyyePxDJqrWlRUpB07dtzyHkmd+h/Spf8atqnH8OtbhU/Kylmc9OV/sOBezfSNbTrPSPg+Tg39lzr68EORPqnt11IsIOWtlHKX3vo1ov+QHCPemHKCH4y8c0WsN6bItYi8M24xvSHan1p7Cg51Xhk2dEvSZTMovzsmfyAmr9erLn/3oODtcXsGhe6MuRmDQrckHe4a+odJYZtHvl5DtmzFTEPuqC2XacplxxdFFkUL9eCmTXLnDv6xceLEiUToluJhOzc3V319fYpGo5rdViq35ZbtlcyoW4pd/1vfUKwnquClgRGDd09Pj15//XWdPXs2cQy9YRjKzs5OzMHr6OhQU1OTZs+enfQ+Iwq1JW1qN/Nl2dERX94W6hvX4A1gArj4Penc/5JiN/1OKfyYdNd/l3zjM/qJ6YdVQZjwIp0R9Z/uU+Bcv6zI8HtoDzKKdY6jWtifV3mL9jt3uujx7qYh12zLUm9Pj7q7u9WV51ZPT486OjrUpS51ZnVJiv9Pz8q6McpimFLu+qG7hXRHhm6b5+1RIthahmTFLEWjUUVj8b24o5Go2i8NPXxmuBXjXq9XBQUFmpE9QzNiRcrPz1emlSlD8YVfhmnIcEmypa5919R/ZujWhVL85M09e/aopaVFtm3Ltm1ZlqVIJKLOzk51dXUpEonvQJLsYJxR8Sf/aDTTDkmukf9IyzA9t//eACaexlels/84OHRL0rX3pSNfTU9NmBIY8caEZQVj6tjbroHzgcRJgq4Ml/LuKxhxjnbmgkx1upRYVPlR7gK33IWjCEpzH5cu/UCyh9taziXN++zQy5Fe6fKPpJZfSlZIKlgjzXtCypp36/e7SeCmI+Gvu37EuSS5/BnK9mUrNhBTf0+/zubVqzJ3heaEy+Qx4iHRO8ur/AcKlTEnY8i9ctw+BcODR3H7M27877Rj1qC9um3blhWzdKzumEpWDp7WMtze3FJ8VDrTlSHTNOUKuxSzhh81ti2p91CPPIUe9R7pUbg5FF+wuSxLjd4m9fb2yjAM2bY95L1CoZCi0eiHJ2WmsMCx/NPSxe8q8UVj2/FdbCI9KrUbNCN/i9pjIckc+h65bp/m+xn9AqaUi99J3tZ1Quo4KBWxdz7GjuCNCav9p60KXho8MmsFLXX+skOuDJeyVgz/0b47z6Psyhz1negdtj1vfcHo9rLNmitV/a10/P8bPOrh8koVfyblrxz8/GC79N7/KwUu37jWWy9d+bG05hvSzPtu/Z4fKvJmqX+gK/E4EokkQndm0K2PnZmlsvalMmQoqqgC/gE98PTG+HOvReTyuuQZ4Y+Lqvwy/aK1btC1ruKo+jMi8g+4ZUbjAddlu5Rh+eS23YoaUUUPx9Q6q0Uz75+V6MOSkhKdP39+2PcJucPyZHhkB+N/Odm2ZNnxTxwSU+xNqetsp1rOXpVsyevxKCMzU6GmkIJWQGa2KZka9v+z6yP0gUAgtYUv/jJp5Z9Ltf9dsqNS4FJ8K0lJ8uTq0e5f6L8sKeovlzw3/uhzydAnipfJxd7IwNQRuib1XRj5OdfeJ3jjtphf+9rXvpbuIjB+IpGIPJ7J/7F3qCmo7v/blbQ9ei2inKrko94ZCzJlR21F2sPSh4OkZo6pgk1Fyr7FkcmD+jB7vjR3p5RZLGXNl0oekVb9lVRQNfSFtX8tdR4Zet2OSe0H4iPkrtGdUOpxuXSm98aOI6FgfJs+X9jUQwfnalZnRmK7QJdc8vX7ZHRIOatz5c5xD9rBZDglGTlqDvaoM3LjDwqX6VKzr0vll3xyR+KhOyvmlylTlmEraIbkNtyKNUVlRl3KXBif0pKTk6O6urpECL55K0Ffpk+rFq1S8HJIkaClmPVh+LY+nOptGuqL9soccClkhOPTSKJRhYJBebwe2QFLVtRSj79XgUBAljX0YwyXy6WsrCzl5OSorGzk495HlLtcKnlIan9HClyRzEwpY5aUMUP5Vp8WRRo1EIupy79QhlxalDVDW0srtDB77Me0d3V16fjx4zp//rx6enqUn58vt/vGOMhU+T5OF/ovddO6D+2IdPHfR35O0T1S4dqkzdO6/zAiRrwxIQUvjbxAMtIRUbQ3KnfO8F/ChstQwYOFyrs3X+GWkAy3IW+JL+lOJiPyZEtzPzPycyI98eklSdu7pNa3pNJPjOotK3JLdDnQpYMfWQS59HKBcvtMGcNsRhRpCmngXED+pcmPtb/ONFz6zJy7VNt9VSd6mtUS7FV/NKzQbJdeve+Slp/P0cpLs2RZlqJGVBFXRC4zviTEtmz1HetVzto8GTmGOjs7NWfOHF28eHHQfto5OTl6+OGH5c8o0LFf9arsIyVbkq5FbGXHXIq5Bk8hsWxbvT29ysrKUlFfoa4Uxk/SNE3zw0N47MTjnJwc+Xy+QQs8b1vWfCnaF/+04yNKYx3a0feGNKdKmv+5236L999/X0eODP4D7eDBg3r44YdVXl5+2/cFME48ufFpgsMNpFxXvNGxcjC1ELwxMY3io/vRHBjo8rmUMdeBI75D7fEpCiMZuDqmWz5aslyVuSU63t2sVqNTly/XafF5n4xwVJbiUy+MD4Oux+2RYbjUerhFZy7Uqbm5WS6XS/PmzVNVVZXy84ceGmQaLt2VP1suw9BPAydlulzyezN0LbdfJ1Z0a3FHsaLBoExLchlmYtGq2+2WbOnKgcva1/YrhUIhSfGR51gspoULF6qiokLl5eW6evWq/uf3D+idYL52yqXFMmQYhqIul0KSIrGYQrZbtnvoYs+YFZNhGPK5fDItUy6XS5ZlyTTNxKj6zSPFN+8rftuigfgfSSMZGLrwdbTOnz8/JHRL8dGxX/ziF/rc5z6nzMz0HkkPQNLip6SDT8c/sfyokk9II2wvioln165d2rZtmx5//PFB1+vq6lRTU6P6+nrl5ORo8eLF+uY3v6mCggI99dRTOnjwoFwul5577jlt3LhxXGoheGNCylzoV/evO5O2e0t8MrMm0Jevb4ZkeJIsxPyQf+xb3c3x52uOP189WT363z97T0bISuyrLduWYdkyTVP+LL9CoZCu1F/RpeJLidfX1dWpoaFBW7duHbT39nUx29IbrfVKDEYbUmZmpqLBoAwZsnxueUI3pneYLpe8Pq9iVkxna+sUyg8l2gzDkNvt1qVLl3T33XersbFRP//5z3W+cYlsw9Z/2VGtlUurbZdybUOWy9BZ2eozYtpkDH+cgGVZKphVoLmL56nvdL/6+uK7n3g8HmVlZSVCt2maWrZs2Zj7dwi3X3LnSNHh1wdIkjKKb/v2tbW1Sdui0ajOnDmjNWvW3PI+tm2roaFBZ8+eVTAYVF5enioqKlRcfPu1AbhJ0d3S2n+Qzj4n9X24hsX0S3Mek5b9UXprw7gIBoPaunXr/8/enQfHed6Jnf++R799d6PRuG8eIAHeJESKpy5Lo4ORLFseO7Ync6YyyWSy60lcu7W7VVuzR9WkdmpnajabnWQrxyaT0SQz9tiWJUWXLduSKVEUSfEEQJDgARB3AZentgAAIABJREFUA+j7eo/9owkQze7GfZLPp0pV4vu8/faDF83mr5/+Pb8ff/Inf8LLL78MwM9+9jNGR0f53ve+B+TK5Y6MjPDiiy9y5syZeXdJns06ilwE4T6tUsO1zV3QfRIAGfxH5tn2fbXYfLn84MF3io9r5VD15KIv/+GHH+J0OonZ45Sn8kvbKYqCzWZjPDROtKzwfmUyGU6dOsWXv/zlgrGb8XHiD1RQcTpdxHSDmDOLJ2nDkiQky0KWZXx+PxISqWSSiLd4cGqaJpcvXyYUCqHrOtlMGv3eZs3PMDkDuFDwlgUITU7ilQ2elExkq/ANTVZkvLt9PPvUsxw+cpj33nuPoaGhvHxoWZZ5+umnl2elWJKh/mW4/XqJcRvUvbToy4+Pj886HgqF5ryGZVl88MEH3Lx5c/rYyMgIPT09HD58mD179ix6foIgzFB5NPdfrDf3bZhnc+7DuTCrnj/oXPHnaP3T9qLHb926xYsvvsjx48c5deoU9fX1/OhHPyp67uuvv86RI0emg25gelX7z//8z3nmmWcAqKqqoqysjM8//5xDhw4tee6ijrewbgVfrMSzz4uk3k87UctUKk5WTW/sW1fa/mkuR/hBigP2/O8gL26jzfj4OMPDw0iSxETlJIqqoCj3/lMVDNMglUyRlbKMeYsHbsPDw9PdJGdKGUXSYyTw+LwMtGWQZRnNoeH1eikvL0dVVMAkJUcIu0oHkXfv3iUUChGNRvEod6drcFuWhWlZxE2dWCqJTdPwe8e5WXkbi/xVb0VW8DR58B/N1SH3eDx85Stf4eTJk2zevJn6+nr27NnDr/7qr7J58+aSc7FMCyNuYOrzqAEPsPUfgLfY6rkMO/+HJTXO0LTZ64HPpyRiZ2dnXtA90+nTp5mYKP1NkSAIi+DZnKtiJYLuDaGnp4d//I//MVeuXKGsrIzvf//7Rc+7fPkyHR0dRcf27t3LG2+8ga7r3Lx5k7Nnz9LX11f03IUSK97CuiWpEuVfqsB/LEB2JINkk9GqtcVtkFwN9nI48h+h/0e5jZZGOlf9pPnr4GpY9GUnJ+/nHMcccW5X9NEUashbIc7IWXqqe9GV0nnmqVQKny+/Ekyto3SFl4FtGbypNI/1VyFbEpgZSI+gqrdoavp/qGSSW/p+ztqeYizoJO5WkbBwR7M0JSWyk9lcGoTaj1PZTNK4/1yWlSsB2FhfxY5gmMlsmKv1XVRFK3GnXVgqbH5yC9VH6vI+eEmSRHNzM83Nc9dFtwyL8KeTxC9GMRIGkirh2ubGfzxQclMukNtM+/i/yf0eB9/Jbbb074Cmb0DZHE2V5rB161YuXLgw6/hcurq6So5ZlkVnZydHj86/dKUgCMLDZNOmTezbl6s81tHRUbTJ21x++7d/m87OTh577DGam5s5evQoijK/qmRzEYG3sO4pDgVlNTZILgfVlat4sYSqFw9yufJXWULecSZdYQLxMmyGjZQtxa7ndxP/ZekW9oqiFATdAEG7my3uIDfixVfKteMeGtyNJC4PYHb/Z+yOazgC10ilk5jRBJp/kFBVhhi5oNpCIuLXuFPrxhMNY5omsgStvlPcie8hnKnBurdL0yWP8+vPV7J728t0dnZy+/ZtkmaaQF2QHTt24PXOXvaxlJShY1kWsR+HSPber45j6RbxqzFS/SlqvlU7+x4B1Qktfxda/i56RCf2RYT0lRQog7ha3bh3epC1hX9huHfvXm7dukU4HC4Y27p1K7W1tXNeIxqdJf98HuOCIAgPs5nfHCqKQjJZvErazp07+fnPf150TFVV/vRP/3T6z0ePHmXbtm3LMj8ReAvCOlddXY3f788L1gzFYMyXC5bLy8tp39nO1a6rJXOEt2zZgsNR2MES4JXanfyX/i8YSOWnorS4ArxQ04Yqq/jK/hLqfjw95rDbSSTTfFTxNIqcQTUz6OTSKBRZRnM6mGjx4+jL1SK3yRm2eD8nY9pJGx5scgqXLQlpH3Z7Pfv27ZteoVisG7ExPg7dpD8ZJjik8XhXOR7Vjl3Of5szIjqRzyMEnpw7ZSTVl2T0h8NYmftpMOm+FLELEap+tRbFvbAVEIfDwSuvvML58+fp6ekhnU5Pb4zctWvX3Bcgl3IzVUmm1PhGZKZN4l0x9EkdxaPgbveguJZnhUkQBOFB3/rWt/ijP/oj3nrrLU6ePAnAL37xC8rLy9m8eTOWZeF2u3n//fdRVZUdO3Ysy/OKwFsQ1jlJknjiiSd45513prtXTrHZbJw4cQKAZ599lrfeemu68seU6urqWVMPXKrGbzYfpDc+Tm88hCxJtHoqaHIF7p809EHBnCYrtpPQfGCaaFISAzt2ux2n04kkyxgujaxHwxa7v3lTk9No8lTQKC9bg4mrkSF+NHB5quE7Nf12MqbBeCZBmebE+UB+faI7NmfgbRkWobdH84LuKdlQlomfh6h4qWrBc3U6nRw9epSjR4/mvhFY4C757du3c+rUqZLjbW1tC57TWkveSDD29kjevQ5/PEHgmSCe3Yv75kMQhLVRauPjWvvd3/1dvvOd7wDQ2NjIJ598wptvvsl3vvMdvvOd72Cz2dizZw9/9md/xsjICM8//zyyLFNfX89f/MVfLNs8ROAtCBtAbW0tr776KpcuXaKvrw9JkmhsbGTPnj3T9av9fj9f//rXuX79OgMDA8iyTEtLC83NzUXbrc8kSRJbPEG2lOrCqBd+VZdSnMiyjCzLKKoDpyuIJEnT3SUVRUGy2yCWXzVlai6yLFNXt/ASiw8yLYufjPQwc+ukot//eaPZFE57fuBdLJh+ULI3gRErUsN3avxaAuMZA8Wx+FXZxZSm2rFjB319fUU3+nR0dBAMLryT5lrSJ7OMvTmCpef/TizdYvyDMWxBG/a64t/WCIIgzNTS0pJXtvW73/3urOe3tbXxzjvFq5F1d3cv69ymiMBbEDaIQCDAE088Mes5qqrS1ta2/KueZbth4lzeoUrjfvUMSXUVND3SbBo+2U5CTk53mpwiyzLl5eVFa4svVH9ykoien3oRDuhU3c3l+RmWRcbU0WaknGi1c1cP0cP5G1UNQyeTyX3joGkaCgpGdGmB92LIsszzzz/P9evXuXbtGslkkrKyMnbs2EF9ff2qzmU5RC9EC4LuaSZEz0dE4C0IwkNDBN6C8BAyLYuRdG6TXZXdizyPTqCz2vRrBYF3lTFJkz7MHVs9aIV11XcF6zGDMQYzBolEYjr4liQJTdN44YUXljane4qVRBxoSbKp24Wazf3c5gOlCr0HCjeaPkjx5gJq3dAJT06S1XUkQJJkJFnC7rBT41ybQFeWZbZt27Zsm33WUmaodL76fMYFQRA2EhF4C8JD5uxEP6dCN6dXgb2qnaPBFh4LNC7+olVPwPY/gGv/d153zi9nO3m94glCDzS/qbF7OVm7A+OlLfzkJz9haGiIbDY7vVnlxIkTbNq0qfTz6Um48zcw8DZkw+DZAs3fgKoTBafWOLzIkJdqkrVbfHE0zN5PfdjSMjYpF0RLCvhPlOPcNHc9XtcWNwP0Mzk2iWnlrm4BWAaSJTEsDxO+EOPYsWNzXksoTbbPnm4jLaJ6jCAIwnolWQ9+B/wISCQSvPHGG9y4cQOXy8WXvvSlh6bbWyKRKCg/JyzMRr6Hn43f4f2Ra0XHvlTZyuHg3PWvZ5Ueh8H3IDsJ3q1Q9RQ6Ml3RYXrjISRJokn1sruiMW+VfWRkhFAohMPhoLGxMa/zZAE9AZ/9Q4yJy7nNpFIubUWWpVxzm63/oOAhP7h7iavR4YLjsgEHQzU8Rh2SU6ZfvkvnzU4ikQhut5u2tjZ27dpVtD5rKpXiR//qhzTdbUB+oNdYSk5xpaoLR8DBt7/97Xk1vlmIjfwaXKh4Z4zQ26Mlx8tOBPAdWlin2kfp/q0UcQ+XRtw/oZRHcsX77bffRlEUvvvd7zI0NMTrr79OTU0NVVULr1AgCOuFbpp8PNabdyw4pNHc46RsTANlktHdTsoOB7AFFllNxF6eq2899ZxRncS1KA1JO5urNuHc4iKZThaktlRVVc3775dx4/8j3n/6Xsm8++kpTqcL9/X/F2qezXWSm+GlmnYSRoZbifyujY3eACfa2tBkhffffz+vkUI4HOb06dP09fXx4osvFgTf165dY0QZZdA3RFO6gTLdj4nJiG2MfvtdzKyJqquMjo7S0LD4BkmPOtc2N7GLUdL9qYIxW9CGZ+/caUGCIAgbxSMXeGcyGa5evcrv/d7vYbfbaW5uZvv27Vy4cIHnnnuOSCRSUI7N4/EUbT6yHs1VvUKY20a9h33JCZLm/Xzn+psO2s97mU5vNmHycpj0jSRVX69Bq1r8Km1CzzD8yzGss0nUGWkmik/F+4IflrDQM3HpP2Cl84Mwy7JIJOJIkoSr/8fQ9t/mjdsVlW83ddCXmOR6fAyALe7gdEnEmzdvluxeNjAwwLVr12hvzy+BFYnk6ponlARdriLfIpi5eS1XN7OZNuprcDEkRaLyq9VEPpkkdjmKmTSRNAl3uwf/scCcqShFr/kI3b+VIu7h0oj7J5TyyAXeoVAIWZapqKiYPlZdXc3t27cBOHv2bEEnoyeffJKnn356Vee5WE7nBunwWMJYOs6dxAQ2WWGrpwKnsjx1nhdio95DY0bWmJKV2HbRwwN7CrHINSqZ/MU4VV+bu0vig9KGznvD3YxenWDn6Vx9ZZus4FMdaLKSa07z4wnkJyQkVcLR7ERxzj8wDYfDmMkRSv2TlUwmcaZGS443uspodBWmJVy7Vjz9ZkpPTw/t7e2kB1Kk+1NIqoRHdqNpGpIkFVRlgdw/rG63m+rq6jl+qoXbqK/BxZJtMmVPlOM/HsBMm8iajKQsPnB51O7fShD3cGnE/RNKeeQC70wmU5CP6XA4pjvBdXR0sH379rzxjdQJLplMbsi/8ClD543By/TExqaPqZLM4fJmnqzcsqpz2aj3sN7pR5VkdMukasCeV8sactX+NDkXBKfupNCjOqp3/m8BpmXxX/rP05cMc+ja/eY6WdNgPBsnaHMjxy0ywwaj48MoTiUXwO71UvZEOZI8dyA1MDCAZgbxycVzfk3TIEY5C22pkkoVpjHMlI1mGf6rAdID9ytolFk+mrONpJwp4ol4wWMcDgcHDx5cVC3uuWzU1+BSSbK0oA9qpTyq9285iXu4NOL+CaU8coG3pmkF7ZbT6fR0MO7z+TZMWkkxG3Wv7A8HLnEjnt/uXLdMPg7dxKnYOFTetGpz2aj30KnY2FdWz+cTfdgyhUGuU9GQp9aKLTBTJguJYHvjIfqSYbDAN5H/1mFZkIpksKdzQaiVtcCZa4ISPRtBkiXKnpi7RbskSdw09rNXfq/ouImCXn1y/pO+JxAIMDx8b/OlBbIlY0omU7dj01ATafLfF2RJZpPZQjab5abnNolEYro5kNPp5MUXXyz4kD5lcHCQiYkJnE4nTU1NC05H2aivwfVC3L+lE/dwacT9E0p55ALvYDCIaZqEQqHpDm9DQ0PL0shDWJzhVLQg6J7p9PhtHgs0Lr0W9SPg2apWDNOkzzeSd9yl2PCp97/pkTQJ07uw+3ktdm8VWgJTsZCM3Cq4BcgWSClrOpB9MBck+kUE3+Nlc+brNjY28rF5kKDRT4NyNW/MQqZT/TpP1iy8dvWOHTvo6eyhZqKKimgQ1VQxZIMxb4iwM4I/64MiWU1Oh5Od6g4c212MhkZxSHH2BW/Q4ulGnrwEN45D41en65hPTk7ywQcfMD4+Pn0Nh8PBsWPH2LJldb+5EQRBENafRy7w1jSN9vZ2PvzwQ1555RWGhobo7u7md37nd9Z6ao+s2w9UonhQRE8TysSptG+clJ+1okgyL9W2Ew62MNDdjzRpYpdVFCkX8JqYRPUM1xuiXL11Hb/qoCPQwOPlzXN+sDEti0w6TTKV4kaFSvOgLxdfSyDrMlhgYKFIErIjP8C2shbpuymcm2ffdel2u2lv38mZKxZ35D00qZfQSBK2KrmpH+DQU68tatNSsCzIMfMIiXBsOu1dMRWqw1VsMjdh00rvJVB1lacOPolNvQ1n/lGulGLk3uDkxVy98UP/mqxWy1tvvUU8np+Wkkql+OlPf4rb7aampmbBcxcEQRAeHo9c4A1w8uRJfvSjH/HHf/zHOJ1OTp48KUoJrqH5rGRPBY7C/Pg1J66vNTPyvSGMqAHkujeG0glGKlN07cxFjmE9xU9HrzOUivKV+t2zXjN7d4xIMoIpS1xoHad2zI2WlcG6//szMZE0GdlW5Pc1z3j56NGjaJrGlSt2hjO5VWK3281jRx+jtbV1fhd5QLwrhivhxB7QSKVSGIaBrMg4HQ5ISxgpc9bcYkmR4NL/nAu6H5Qehcv/Gz3ePygIuqdYlsWFCxdE4C0IgvCIeyQDb5fLxTe/+c21noZwT6unkveHu/M6D85Uqbkp10QjgoWylWvU/lYDia446f4UvalxPi8fZ7wqWxAEX40OcyDRQLMrUPRa4+PjjJzvQtvsJuZWyWg67x7uZ9+1II3DbnTFxFQsdM3Cclo4Hni8bJexNzx4tNDQ0BB9fX1IksRzzz2HLMvIskxVVdWSynMlunIlQhVFwe12541Zdgs9opcMvLUaO6p1DaI9pZ9g4jzjk+dmncPg4ODCJi0IgiA8dB7JwFtYX/w2B/vLGjg72V8wJsGqVzV5mMg2Gc9uL57dXl6/3kVEz5Y893J4sGTg3d3djWRB050EXdu9mIpE1J3lo/1DqDq40wp7JmrZctWNWmRp23vQX3wV/J5MJsO7775bEJw2Njby7LPPFg26jbhB7HKU7FgG2SHjbvdgryse3Jvp0hudJEVC9Zd4K5Sh7HgAkpdLPn6KkwmgdG30lah+IgiCIGwsIvAW1oVfqd6OS7Hx+UTfdBOYcpuLp6u2st0r0oCWQ8rQZx1Pm6XHE4kEALasRWAiS9ivYsoSkgWyaZFWTW62JzBlaLt+v1SK7JTxHfTjOzh7y++f//znRVeE+/r6OHXqFE8++WTe8WRvgrEfj2Dp9wPq2BdRPLu9BJ4LFgTqWrVGZii/aslM7p0etGo70bPh6dQcrdZO2bEAjmYnTMydIlLZuBtul64X3tLSMuc1BEEQhIebCLyFdUGWJJ6o3MKRYAuj6Vye7Gg6ytXIEFcjQ2x2B9npq8EmL3+XwEdFjcPLnWSRHOV7qh2lawv6/f7p/y+bzBD1qcjGjIY998rl3d6eYNfj9VRlcx+W7LUOJLV0ioiZNoklYiW7SgJcv36dQ4cOTdfENRIGY2/mB91TYpeiaDUanj35JUE9+3zELkUpms8kg/eAH3uNHe9+H3pYR1Kl/BrngT25NvXR65CZBD0KlgmKE7QABA/S0PYEVdcmGRkZKXgKTdPYu3dvyZ9REARBeDSIwFtYV2yygle183rfWcYyienjndERToVu8e2mDvy2uXOFhUIHy5u4c7d44K3JCvv89SUf21rfyvBPh3ClHOiygcOI0dOSmc4Vdzpyv5PdvlpavRU43KUbR1iWReyLKNHzYfSJLJlMlFajmtuBCdK2wlVpwzAYGxujsbERgPiVaK5OeAnRL6IFgbdWoRF8sZLxd8fyAnZJkQg8G8Rek0sRkWQJW6BEhZO278LPXwY9NmNyqdyfd/1PyLLMSy+9xKlTp7hx4waGkVs5r6mp4dixY3kfXhYrYxpcDg9yOzGBLEm0eirZ7q0Um48FQRA2CBF4C+vOm0NX84LuKRPZJD8evMKvNXWswaw2vjZvFU9UbObjsd68hV+HrPJa/R7cqlb0ccneBJEfT7BN30I0GcPC4vHOAJsHopzaPYAt6KO1ooF9ZfVs91SSTCZnncfkh+NEz4chPQaZCWxmlibDoi7tpav2LkNqRcFjbLb7wXB2JAZmGiQFpMK3sGwoU/R53W0eHM1O4ldjGGEdxavi3uFBcc/zW5ThD8BZA5kJ0O9VL1E9uRXvnj+H+lfQNBdPPfUUhw8fJhKJ4HQ68XoX2mezuPFMgtfvnCOs3+/CeTkyRI3dy7eaDuBUSpdEFARBENYHEXgL68p4JsHNWZrp3E5MMJqOrVpNbzNtErsYIdEdx8paaHV2vAf8aJXFg9T17kTFZnb5arkUGSSpZ6iwu9nlq8WuFH8rMFL30zrsdgeqaiOZSmLoBg2pCn5L3kTL45umc6ozpsHF6CAjk0kUSWa7t4rN7uB0ycjseJboFxFIDk6X5ss9VkI1FfZGsmQq+hk3G6bn4PV6qa6uzgW8nX+C3C9B7HFAApsXHNUg3Q86FUfpQFpxKvg6FrHybKRh4L+CbANHkT0HehyG3oeGLwO5pjkOx/1vZmKxGP39uc3DDQ0NeDwLf/3+4O6lvKB7ylA6yjtDXXOWgxQEQRDWngi8hXVlPJNgrka7oUxiVQJvI24w/F8G0SfuVwLJjmdJdMYInqzC1eqe5dErR9d1Ll++THd3N4lEAp/PR3t7O+3t7fMquRfQnDxRsXlez5W4GstL61AUBY/7/r1X+pTp5xxLx/mrvnNMZpLTFTy+CA/Q7Arw9YZ9aLKSK+tnpAvqYcuyjGkaGNHdtFf/S35pfgPIBeWPP/44kpGCz34XYr24K2qIDjwOWJCNgJ7M5V9LCtlshnQljI6OLm832swEGLOv5JMs3BxqmiYff/wx3d3d0y2kJUli27ZtHD9+fN6t5O8mwwyloyXHu6IjxPQ0HrV0VRVBEARh7YnAW1hXXPP4unw+5yyHyV+M5wXdUywDxt8dw9HsRNZWN7fWMAzefvtthoaGpo+FQiE+/vhjBgcHeeaZZ5ZU7/pB2SI/f958ogZm1kRSJb5/9wIRvTBH+3Zigp+O9PBCTRtmxoRsYQApyxISCqYpUSENoJIiWN3MgQMHcrndd74PsV4ANPcQ3tpPiA4eyT3YymIkRwmnNOJKgq7Raxg/MKisrOSZZ55ZltxqtEBuI+VswbeztuDQJ598QldXV94xy7Lo7u5GURSOHz8+r6cfSxdvzDPFxGI8kxCBtyAIwjonduQI60qd00+lVnoludzmpNE5e2m65WBmTBLXSgc7Znr28ZXS2dmZF3TPdOPGDfr6+uZ1HUu3iF+NMfGzEOFTEyUD7Lnyn2W7jKRK3EqMF83Ln3IpPEjG1NGq7RQvLZLb2Gj3TFJR6eLb3/xVvvzlL09vqGT4J3nnBlreIbj5r9Ec15HMKKp+FXvgx4Tq38NQcpsaR0dHefPNN8lkiud8L4hih9oXZhl3Qc1zeYfS6XRB0D1Td3f3nPnwU1zqfD6Qbsz0J0EQhEeJWPEW1p0Xatr4z33nyVr5AZoqybxQM790iqUyk0bRcnUzGdHZ62KvhJ6eWbonAteuXaOpqWnWczIjaUZ/MIwRM6aPhT+dxHvAR+CpYN657nYP4U8mi8bKFjBWbudn70QYysaJBjS8lcWD3IxlMJFJUrXNw6TPiTFafG7e2k9RfJtQZB26/gyi3WDzQ/w2WBZM/e7NDG7nD3Fv/h6GaaCbMg6zkiASFzLPc9PIbcCdyCT4m85PUcq9OBUbu3y1bHaXL+41tO33YfISxK7nH5dssOd/BTW/u+rw8PB0ZZNiDMNgeHh4XvW9N7uDuBWNuFH8/tY5fFTY1yb1SRAEQZg/EXgL606TK8BvtRzi09BtrsfHsIAt7iCHy5tnrTW9nGSXgmSTZi1bp/pXv4pEKlW4uW6muVZQLd0qCLpzAxA9G8FWbssrxaf6bZQdDzD5i4m807O6xY2oxZtpi8ydJElDYjJbQ6A+wabDIzzYpFECnIoNSZGo/Pp2Rv/9LYxE/mq6p+YzPNWfQdkr8PGvgjXjg01qFMwUOBtywXdqZHrcMi10S7v3PBa7tQ/oT+4g5PMyUOfElhrFF88FrJcjQ+zwVvPlul3TGz7nTfPD4X8Hd38Mg+/l0k7KdkPzN3I55g+YT6fK+XazVCSZF2va+Nu7lzAf2AWhyQrPV7fN72cQBEEQ1pQIvIV1qdLu4eW6nWv2/LIt14I8drH4hjbZIePc5io6tpLKysqIRktvsgsEird8n5LojhUG3TNEz0YKamD7DpZhq9CIno+QHc4g2SV+NgpnXCpZORe8OuRco/iJuy7sV8po2hfJu0aLqxzfvfrrWpWdut9/nMS7f05mREdW0rgqLmJzRaD51+DOX4Olc83WwFl7G2NKGU5vkt3hUxzI3MKmefLyxC1JImXeX+1V0KnUerhUdwyrSGx9NTpMw4Sfg+WzfzNQzMiFTvo+uEVyNIAzuJWGL32J6iJBN0BtbS0Oh6PkhyW73U5dXd28n3u7t4pfb36MT0O3uZkIIUsy2zyVHC5vFqvdgiAIG4QIvAWhBP+JAOmhNNmR/K/3JVUieLIKWV39LRI7d+4smcctSRI7duwAID2YIn45hhHTUctsuHd70So0MsOz5ztnx7OYGbNg06hzkwvnptwHjcs30pz6m4m8HSKSJOGzOQhnU4z2emnYHWGqyahDVvlSVWv+XN3VuL/6h7gnvoDJy6Aegeqnof8NMDP8zLmfXzrul8eLyC6Gy0/Sme7jW/EPmc5mlhSyahDTyI+wR8t800G3Zi/ccHhusn/BgffVf/tvufPuu9N/jt25w+j589Q/9RS7f+/3Cs5XFIUDBw5w6tSpotfbv38/qrqwt+B6p5/XGvYs6DGCIAjC+iECb0EoQXEoVH+zlsTVGIlrU3W8HXj3elHL1qZZSVNTEwcOHODcuXN5xyVJ4sSJE5SXlzP5i3EiZ8IzRpNEz0cIPFWOpM2eXiGp0qwt3gH6hu9txDSz95rJRMGycKkuFFsZsayCkdRw+Uy2e6s4GmyhXCvx7UBgX+6/KfE7DCuBvKD7/uRk7jqaOVP/v3Cs67/PpZqoXuymSSIziTVjT0DIlmvCoygKjiKB9/gsG0GLGT1/Pi/onunuz35GVUcH1Y8/XjC2a9cuFEXh3LlzxOO5zbhut5t9+/afbI/NAAAgAElEQVSxc+fafaMjCIIgrA0ReAvCLGRVxrPHV5B+sZYee+wxNm3aRHd3N/F4HL/fT1tbGz6fj+SNxANB9z0WTPxsnOBLpWtbW1jIW+xkMdBQuRYd5czEHQaSETRZYYevhiPBZlwOGcwMxG+BOSMPO5PBng2jOer5ZzuO43Ut4hsBRwUXta2lxyWVC1I5x7b+A7j1n4BccO33+4nFYuh6lqTlI50tR9O0XKOaIrnc7lnK7um6Tk9PD729vei6Tk1NDfzkJyXPB+j7yU+KBt4A7e3ttLW1EQrlGkOVl5fPO7f7UTM4OJj3um5vbycYDM79QEEQhA1CBN6CsAEFg0GOHj1acDx6IVLk7HssSPel8Oz1ErtwP0faxCKaTRFRM5yuuU22pwuvaieUiSNLuQAxYxh8NnGHrugwr23pQE3fRTeLVHWxLHa6P8br2MyiqpXWv0xs6Hrpca2MqJ6G1n8E0R4InQbAZlMJBMrISm7MTX/Ityt28Jcjl0peZo+/sOY25EoAvvnmm9NBMuSqkzjPncOv62ha8ZJ9qbGxWX8sSZKoqKiY9ZxH3S9/+UuuXLky/ee7d+/S2dnJkSNH2LVr1xrOTBAEYfmIZRdBeIgUa/gzU3Y8S+BLQQLPBFHLVCwsQnqc3roYnz05QdJjkDZ1OqPDhDKJ6W6LUyJ6ms/Dl/hyw/eKXt+lJnm16Xsw+svF/QCuBgIV+4uPKQ6wBwlqrlxd7cf+BXT8GdS/nKuh3fZPsT3zJtXbnqalvJoTJbpz1ti9HClvKTp2+vTpvKB7iuFyEY1GC+7HFMdydsl8BPX29uYF3VMsy+KTTz4p+jsRBEHYiMSKtyA8RBSXgj5Zur644sq1ePfu9+HZ5+XcSD/vjQ1jzqjslzRywbthmSSMTEFaRmd0lH/W+BFBR4j3+5/iZqQJVdY5UHmJF5o+oNIxDOkShbrnYf/W1/ik+13M9AQYKZCUXCk/LQCSzP6yhtyJkgyVx3L/FfFExWZq7F7OTvYxkorhVGzs9tfSEWhAkwvf+rLZLNevF662ZzIZktXV+G7eJBQK4XQ6cTqdeekijc8+u+ifdy1ks1kmJiaw2WxzVsJZDVevXi05ZlkWnZ2d8+7yKQiCsJ6JwFsQHiLunR7SA4Vt22eOT5Ekia70SF7QDeSt6qYMvSDw1iWVjOzgQOVlDlRexrQk+tQqznCI7/NVEs4ULWkPxxKTNLgW3mXUb3NysvEQbw1eLejbs9Nbzf6y+nlfa5u3km3e+a1GJxIJdD3/Q0symcxtigwEUFpa8N65QyKRIJ1OU1ZWhizLND77LNUHD857TkthZkws00JxzN5RtBTDMPjss8/o6uoim819wCovL+fw4cM0NDQs51QXJBwusi9hAeOCIAgbhQi8BWGDyYykiZ6NkLyTIGnpGM0K1YcqCAQ9uHd6SfQkSN0qbKTj3uHBscmZdyxrFtb0VqT7K7kWhakVHs2Fo/IoDH8AwLX0AW5f/xqNEz4aAUM1Gdgs8Xr2LK817WWLZ+G5zXv8ddQ5/JyfvMtoOobr3mr1ZndwxTqXOp1OFEWZ7jZpmuZ0JRKASHs7SlMTzr4+zFgMva6Ow7/xG1R1dKzIfGbKDKcJn5ogeSsJJtjKbXgf8+PZvbCGUh9++CG9vb15x8bHx3nnnXc4efIktbXFc99XmsvlyrvXxcYFQRAeBiLwFoQ1ZFkWUT2NLEl4Zqm0MSXZm2DsjRFimTQxPY1pWRCC0OVJIi+pPNveTuWr1cQuRoldjmJEddSADc9uL+6dnoKgtd5Zxt1U/oZMp2IjqqexsLDJhSur+8sakBv/O4j3kh6OE+76NcqMe5sOJVBMB403ZFxxhffs1/iHiwyWK+xunqvetuDHLZamaWzatGk63eTBxjeSJCE3NZFpbsaUIOrWONQ+SwWWZZIeSjPy14N5XVSz41nG3xtDj+iUHZtfqkgoFCoIuqeYpsnnn3/Oyy+/vCxzXqht27YxOlo6PWnbttV7HQiCIKwkEXgLwhq5GB7gVOgWoXs1pescPk5UbGZriRViy7AYf3+MeCZDJJsfFKoZCenjFD/yX+ZrDXvx7vfh3T93CcTHAg2cn+wnO6MGtiRJBDQnk5kkbiW/ikerp4JjwZZcfvWR/0jfX50B05HrCS/JuXxsckF2cEjj5kCCgboI9U7//G8McCcxwdmJfiayCTyqnb3+OrZ5KldstXvK4cOHGR0dJRwOF2yk9Hq9IEmMVNmZCNgwZYl/c+s0VQ4vT1dtpdWzMhsswx+N5wXdM0U+m8S714vimfut/NatW7OODw4Okk6nsRepe77S2trauHXrFnfv3i0Ya29vp75+/ulFgiAI65kIvAVhDXw2fof3R67lHRtIRfib/i/4Sv0e2rxVBY9J3UpixAzievEc7sCYjavDIUYrY1TaPUXPKXiM5uK1+r38aOASyRnlAX2qg9fq9pAwsgym7tfx3uQunz7Hku0Yw9UgF6a1TKkesJMyZq+08qBfjPXy0djMldkoPbExdvpqeKV2J/IKBt8ul4tXX32Vzs5Ozp8/TyaTQVVVnE4nqqoyUOcg7M81T5JlGUmSGc3E+V7/Bb7esG9RaTWzMeIGqTvFW84DYEKiJzGvD1mm+WDG/OLOWQmKovDCCy/Q1dXFtWvXSCQS+Hw+duzYwZYtW9ZkToIgCCtBBN6CsMoyps7Px24UHTOBD0d62F5kddeI6+iWiW6VDo60lExvPDTvwBtgiyfIP9l6gq7oCOFsEp/NQZu3Gq1ImkkeC2zW7OcoBguay0Ay/EDQfd+VyBBb3EF2l6jBvVzsdvt0Z8nXX3+ddDr3QSejSdNBN4DD4Zha3Mck94FhuQNvMzuPYDkzv2C5rq6O8+fPlxwvLy/H6XSWHF9piqKwc+dO0dFTEISHmqjjLQir7EYsRKbIpsYp49kkQ6lowXE1YGO2tV5LhqTbRJr1rOJsssJufy3HKzazx183d9ANSLKEu8GJXSn9+d3V5MZnc8x7HucnC1MNFjK+nGw2G88++yw2Wy7YjnrvB902TSvY8DeQihAr8W3EYqleFcU1++/CXjO/1JC6ujoqZ6k3vnfv3gXNbTVYhoUR07H04qk2giAIG41Y8RaEVZa1Sgfds53jaHTiqLCjDibQi6QEjNamyTrMkjniK8F3sIzk3RTjVpzsA3OyfDInDm1f0PXC2VnSKoBwtnRay0qor6/nG9/4Bp2dnZyJDhC2Z7Hb7WianWKfb4xZvo1YDEmR8Oz3Ef7lRNFxW4UNe9P8PthIksQLL7zABx98wODg4P1r2Gx0dHTQ2tq6LHNeDmbGJHxqgviVGGbKRLJJuNrclB0rR3EvrpSiIAjCeiACb0FYZQ3OMiQoUqgvR5MUquzFy8QF/04Vkf+cZDKcyDse8+l07Yuyw1tNubZ6pdecW1wEv1SB8pFMMpUlbepYloWzykHzVxpKtlgvZa7V8YWsni8Xl8tFR0cH1Ykt/Ic7n5c8r9zmxKcu//x8h/zo4Szxy7G842q5jcpXqxe04dTpdPLyyy8TCoUYGRnBZrPR1NS04N/TSrIMi9G/HSJ99/63B1bWIn4pRro/TfW3ahddx1wQBGGticBbEFZZueZiq6eCnthY0fG9ZXU4SqRvaBUaW//+Zjo/62PwxjhpdEZrM4w2ZdhTXs+zVatfds27z4e73UPyehwzbWJ4TcpaF9cNcZ+/jgvhgVnG1666RYOrjCZnGXeSk0XHDwdbVqTqiiRLBJ+vxNfhJ3EtjqVbaHV2nJtdSPLini8YDBIMBpd5pssjcS2eF3TPpE9kiV2I4n984Y2ZMpkM8Xgcp9OZy88XBEFYA5L1YM0sYUNLJBKi2cQSrcY9TBlZvn/3IrcS+SkEO7zVvFK3M6+JTSmmZdGfnCRrGtQ5/TgV25yPWQ1LvX8fjlzn1PitguNt3iq+Urd7RauazCVpZPnhwGV646HpYzZJ5ljFJo4FNy3p2ul0moGB3IeOsrKyddHKfS2M/nCY5I1EyXFbpUbtr8/+AWzmazCdTvPpp59y/fp1DMNAkiSam5s5cuRIrkSkUJT4t2RpxP0TShEr3oKwBhyKjW83dXA3GeZWfBxZktjqqVhQBRBZkmhyPXzB2dNVW2l2Bzg30c94JlfHe19ZHW3e6jUNuiHXXOibjfsZTcfoT4ZRJZlWTwWOJXzosSyLM2fOcPny5emW9ZIksWvXLg4fPrzitcvXm7mqtFjzrOICYBgGb775JqHQ/Q9KlmVx69YtRkdH+epXv7qmlVwEQXj0iMBbENZQvdO/4OYy600km+KziTt0R0fQLZM6m4djVVupc85dW7qUze4gm93rMxUCciUSF/IhaTaff/45X3zxRd4xwzC4dOkSkiRx+PDhZXmejcJeYyfdV3qTrVY7/wY/169fzwu6Z4rH41y+fJmDBw8ueI6CIAiLJQJvQRAWbTyT4C9uf07MyEwf68qMcf32BK/W7aLdV72Gs1s5o+kYZyb66E9MYpMV2rxV7C+rL1j5zpoGXdERJrJJPIrGDl9NXv5+Npvl8uXLJZ/n6tWr7N+/f026Sa42wzDo7e3lzuRtKmNBNEXD4XAgz0y7kplXs6ApN2/enHX81q1bIvAWBGFVicBbEIRFe3+4Oy/onmJi8V+HOtnqqcA2j5rgG8m16Ch/O3ARY8b2mIFUhC8mB/j15sdwq7kKITfj4/xg4BLJGZ07fzLSwws1bdNNgIaGhshmS3f21HWdwcFBWlpaVuaHWScymQxvv/02IyMjAIz6R9k82kIykcTn92FTbUiqRODZIPa6+W+MNIzZS3dOpfYIgiCsFhF4C4KwKDE9nbfJ8EFJU6cnNkq7t5pbiQlG0lHIGjQpHoK+skWXsBsdHeXKlSuEQiHsdjutra1s3boVRVn5AD9rGvx48Epe0D1lPJvgJyPXeKVuF5Fsiu/1XyDzQD32jGXw5uAVyjUX9U7/vPK3H4Uc708//XQ66AaIuKJcbLxCIF6GT/by+JOP497hXXAZwZqaGu7eLd10qaamZtFzFgRBWAwReAvCQ8ayLGJ6BlWWV7TSSVzPMNc2t6FUlI/HbjKUCBOLx8lmMsimRc2YzuGqTRw+fHi6M+R8dHZ28vHHHzOzGNPAwADXrl3jpZdeQpFlGPsEQqcBGapOQPmBxf2ARXRFR0iZpVdJO6MjPG/onJvsLwi6p5jAmfE71NfvpqamBrvdPt2W/kE2m43a2trlmPq6lc1muX79esFxUzYJeccJMU5r+XZ8joWXEGxvb+fSpUtkMoXfysiyzO7duxc1Z0EQhMUSgbcgPETOTfRzevw24/c6PDY5y3iycsuKVD/x2xyokoxeqlujZfH5RB9pPctkOIx1r7OlKUsMVNn4rK+H8fFxXnnllYJVXdOyuBkPMZKO4VI02rxVZJOpgqB7yuDgIJfO/oJ9+r+HyNX7A7f+AsoPwoH/E9Sll/aKzNFZU7dM4kaGu8nwrOfdTeXGVVVlz549nDlzpuh5u3fvXlfNbVZCPB6fM+VjcrJ47fS5uFwuXnzxRT744APi8fj0cVVVaWpq4tKlSzidTlpbW9dtXXNBEB4uIvAWhIfEL0Zv8FEofzPZneQkr/ed4+827KfFXb6sz+dQbOzwVXMxPFh0XJZkMqZBIpGYDrpnGg9qDN8e5vbt23k5zKPpGN/rvzD94QHgveFuNsWUokH3FOf1fw7lRVJfxs/A1f8D9vzhvH+2Uvy22UvP2SQZj6rNmdduk+6P79+/H0mSuHDhwvTKt6Zp7N27lwMHlm+1fr1yOBxIkjTr73Yp9ZCrq6v55je/yZ07dwiHw8TjcTo7O+nt7Z0+5+LFi+zevZsjR44s+nkEQRDmY+4uHYIgrHtxPVO06QyAYVl8OFr4Vf5yeLZqG7WOwiYkTsXGJlc5kiQV/ZofIOFSsMivPJExdV7vO5cXdEMuN/qsGSLuLh7QeqQxyo0uSoZug+9Cenw+P9Ks2rxVeek7hmUSzaYYzySYyCSotHtQJYV27+zVXB6s9rJv3z6+/e1vc/LkSU6ePMlrr71GR0fHI5Hf7XA4aG5uLjmuaRqbNi2tOZEsy7S0tNDa2kpXV1fRTZeXLl2ip6dnSc8jCIIwFxF4C8JDoDs6UnTD35SBVITwA8HscnAqNn6j+SBfrt1Jm6eKre4gJwIt/MNNRwhoudXhUiuZkgUS+ZUlLoeHiOnFA3VZlgkFi6ddlMlDyLJCyTDVykJ06R8+VFnm1bpd2CSZtKEzlo4RNzJkTB3DMrmbDPNXfedo9VRQ7yhenz1gc/JYoLHw2qpKfX099fX1C8p7fxgcOXIEt9tdcFySJE6cOLFs96O7u3vWtJarV6+WHBMEQVgOItVkHlKpFGaRr8rXI8PIfbUvLN5GvIfxVHLO12g4HsemlQ7Ol2Kzzc/m8lygaRgGZHSabT4+M01UVSVTpGSeN5zBNE2CweD0/e6NjJb8OTRNI+xSio5nJA273Y4xyz3I6ArWMvxeayQn36jaxb/uP4OCjCRJOGQVh6xiWRa9sRA/H+rh1Yo2Ppq4RWdshLRloEoS21wVnAhswkpnSVC6jOBGfA0uhaIovPDCC3R2dnL79m0Mw6Cqqor29nYqKysXfC9K3b/h4eFZ/56Mjo4+Uvd9No/aa3C5rcX9Ey3qNwYReM+DwzH/urFrLZFIiL98S7QR7+EmKvlF+HbJcZdio85Xjiqv/JdcU/evzeWiNTFMl2GQfWBznGxaVIayuN1udu3aNb2B0KnZkZPF5yjLMgFfGYoSL1hFV6uP4nJ/gZwtsQnP1YSz+gAsU+rGRGYCt82O21a8sc3VxCjP1bXzsmc3L5omcSONU7GhyfN7y526h0kjy4XJAW4nxpEkie2eKnb4qh+62uiQCxqOHz/O8ePHl3ytUn+HPR4P8ix/B5xO54b7u79SNuL74Hoi7p9Qigi8BWEFGJZJytCxy+qqBLsNrjLqHf7pahkP6gg0rso8HvS1+r18qLn41LzBRDSCZVm44gbVIymqnF6ee+65vKodbd4qvggPlLxeR/UmDr56sGgdb3nIDpf+EB7M9JYUaPunyxZ0Q65j52wSRpakkcWtaqiyjF+efVNmMaPpGH955xzxGQ2KemJjnB6/zbebOqYb9Qjz19raOms6SWtr6yrORhCER5EIvAVhGWVMnZ+P9nIxPEDK1NEkhZ3+Gp6q2IJrhQOlrzXs4a/7v2AwFZ0+JgF7/HUcDy5tc9piqbLMc9XbebJyK2OJKCN3B1AyBmU7y2hoaCjYPLjZHaTFFeBWYqLgWk5Z5UiwmYDm4qmnnip8svqTYPND77+DyYuABMGDsOXvL2stbwCPOnsLd5skY5/n6nYpP7h7KS/onjKaifPOUBevNexZ0vUfRdXV1Wzfvp3u7u6CsbKyMvbu3bsGsxIE4VEiWbPVcBI2HPH11tIt9h4alsl/unOW/iI1nCs0N7/RfBCHsvKfdW/Gx+lLTKDIMm2eKoL2wk1rK2mpr8GsafDT0etcDA+QMQ0kcgH5l6paqbR75ncRPQmSDMrsAfJixfUM/+LGRyU3tO7z13Gydseir989Psj3Rq6UHJeBf7L1xJwfAB5Vs70GLcuiq6uLK1euMDExgcPhoLW1lX379m2otMKVJv4tWRpx/4RSxIq3ICyTq5HhokE3wFgmzvnJfo4EW1Z8Hpvc5Wxa5prdq8kmKzxfvZ2nK7cSziZxKdrC0yrUB1I79AQYSdACuYB8idyqxq9Ubeed4cIShuU2F09Vbl3S9SfnqEBjAhOZ5IYJvPWoTvRchOSNBFgWjiYn3g4/tvLVr94iSRLt7e20t7fPep5lWYRCISzLory8HEV5+PLqBUFYfSLwFoRlcjUyNOv4lcjQqgTe68mdxASXwoMkjCwVdjf7/fWUafPLd9ZkZf4r3KVEb8C1fwmjHwMmOGqg+ZvQ8q0l53wfCDRQYXfz2fgdBlMRNFllh6+axwKNebW+F8OtzP1Bw7NBcrwzYxlG/noQM3m/mkhsMkq8M0blV6pxNC48/32ldXd3c/bsWWKxGJDbdLlnzx6RiiIIwpKJwFsQlknGLGzKMVN2jvGHiWVZvD3UmbdR8lpslNOh27xSt5MdvpqVn0SsF07/Duix+8dSQ9D9p5C4DTv/xyU/RZMrQJMrsOTrPKjFGcCjaiVrmjc5ywhoG+Nr7In3x/KC7ilW1mL83TFqf7sBSV4/jYI6Ozv56KOP8o4lk0lOnz6Nrut0dHSs0cwEQXgYiAY6grBM6pzFG6ZMqZ1j/GFyMTxYtDqJgcUbg1eIZFMrP4mef5UfdM/U97cQu7Xyc1gkWZL4OzU7UIukxTgVGy/UtK3BrBYuO54lPZAuOa6HddJ9q/BamCfTNDl79mzJ8QsXLpTsxCoIgjAfIvAWhGVyoKyhaKAEub9oh4p0K3xYfT7RV3LMsCy+mLy7shMw0jDy89nPGXpvZeewRFs8Ffxm80H2+GrxqXbKbA4OBRr5nZZDC0rBWcv980asdJfIhZyzWuZqoKPrOv39/as4I0EQHjYi1UQQlklAc/Ja/R5+OHCJ9Iy0ElWSeammfc4V8YdJKBOfdXxsjvElM9NgzZHao6//rnzVDi8v1+1c8OPC4TDnz5+nt7d3ugvk7t272bx58wrMsjTVr+ZqWs4S+6uB1d9gWYphzJ0OtlG6GAuCsD6JwFsQltFWTwX/zdYTXIkMM5FJ4LM52OmrWfJmu43GrWpMzpJOMp/Ng/MxnknQn5xElRS2uIPYp8o12nzgaoLEndIP9i88oN0IJiYmeOONN0in76d4DA8PMzw8zKFDh9i3b9+qzUX123C0OEndLF6lxVapYa9bPyX8KisrsdlsZLPZouOSJFFbW7vKsxIE4WEiAm9BWGaarLK/rH6tp7Gmdvvr+Gist+T4Hn/dkq6fNnTeGLxCT2x0ejFVkxWOBzfdrxzT8i24+s+LX8BZB9VPL2kO69Vnn32WF3TPdPbsWbZv347TuXqVRMqfq2DkrwfRJ/NTShSXQvClylWbx3zYbDZ27tzJF198UXS8tbUVt3t16+ILgvBwETnegiAsu8PlTdTYvUXHDgWaqHX6lnT9Hwxc4tqMoBtyVWV+Onqd81P5401fg5Zfo+BtzlkPHf8XLLGz5HqUTqe5c6f0Kr9hGNy4cWMVZwSqV6Xm79UTeCaIo8WJo9lB2YkANb9Zj1ax/koiHjx4kJ07dyLL9183kiSxdetWTpw4sYYzEwThYfDw/csjCMKa02SVv9fcwZnxPi6GB0kaGSrsbjoCjexcYinBoVSEG/FQyfFPQrfY669DliRo+w40fT23kVKPg38HVD4BskJCz3A5MkQkm6JMc7LTVU32YpL4lShG3EAts+HZ48W9y1PQ2n69ymQyc26mLLUavpJkTca734d3/9I+cK0GSZI4duwY+/fvp6+vD8uyqK+vx+st/kFSEARhIUTgLQjCitBklWMVmzhWsWlZr3szPj7r+EQ2STibvF/n2lUHm38z75xL4UHeHupEt3Ib5WQDxn85QkvYi0PO5eNnhtKMD6VJ96cIvri+UiJKcbvdOJ1OksnSnS+DweAqzmjjcrlcbN++fa2nIQjCQ0akmgiCsKHI81h9nu2cgWSENwevTAfdAPU3nfhHVSYzybzjAPGrMZK3Zm/hvl7IskxbW+ka316vl+bm5lWckSAIgjCTCLwFQdhQWj2VzBZ6V9s9+G2lNw9+PtHHgwXhau/kKmtYQMIobJASvxJd+ETXSEdHB5s2FX7L4Ha7ef755zdM2owgCMLDSKSaCIKwoZRrLnb7a7kYHiwYk4AnKrbM+vjBVKTgmJa+vwaRNQtrOZuJues7rxeyLPPcc88xNDREb28v2WyW6upqtm7diqpu3Ld8PaKT6I5jZkzsNXYcm5zrqtW8IAjCfGzcd2FBEB5ZL9W041RsnJ+8S+ZeoBywOXm6civbvLPnY9tlpeBYwqPjSOQqbEhF1tPV8rWvvtGXmORSZJCkkaXa7mVfWR0e1V7y/JqaGmpqlraRdb2Y/HicyJkwM7+qUAM2Kr9SjW0dNeARBEGYiwi8BUHYcBRJ5tmqbTxRsZnhVAxVkqlxeOeVRrHDV8PdB1a9+7YkKR/JBdeOB5sdyeDdu7iKFqZlMZyKYmJRbfeiygvP7jMti7cGr3Ixcn+Fvys6wqnQTb5av4etnopFzW2jiF2MEDkdLjiuT2QZ/dshan+rQax8C4KwYYjAWxCEDUuTVRpdZQt6zL6yOi6GBxhOx6aPjdZluL0tQet1L05lxtuiDOVfCmJbRL3pC5MDfDTWS1jPdfB0KTYOBZo4GmxZUJ71ucn+vKB7StYy+du7F/n9LcdxqWu/Ir9SomcLU4Om6JM6yesJXNtEUxtBEDYGEXgLgvBI0WSVX2vq4BdjvVwKD5IydZyySvDJClqP1ZG5msyr472YVIYLkwO8OXQ171jCyPKzsRtkLIOnK7fO+1rnJvpLjmUtk4vhQQ4HH85KJWbKIDtevH37lPRgWgTegiBsGCLwFgThkeNQbPxK9XaerdpG2tSxy+r9EoR1SwviTMvip6M96KaBIskFq9ufjd/hcHkzzgdTWoqwLIuxTHzWc+Ya38gkVc7V3nqwDM0Msk2kmQiCsHGIwFsQhGVzOTzEZ2O3mDTTeBSN3f5aHgs0YiuyoXE9kCVpXgHwfI2mY/zw7mV6Z3TWdCo2fKpjOgDXLZMbsTF2+WvnvJ50b34Jo/Sqr2sZ57/eSKqEc4uLZE+i5DlitVsQhI1E1PEWBGFZvDvUxY8GL3M3HSFpZBnNxPnp6HX+8s65oiX6HjaTmSR/cecs/anJvONJI8t4JpErEn6PMUdb95l2+2YP0HfPI4DfyPxHAsj24v9UuXd7FpV/LwiCsFbEircgCEvWn5jk88niuch3U2E+n+jjSLBlXtfKZrP09PTQ19cHQGNjI62trdhs63tl9/T4bZJGFhsa7hgAABEJSURBVJukICFhzYi0s5ZBysziUGzIQIs7MO/rHqvYxI34GGOZwlXfI+XNVNo9yzH9dUur1Kj6Ri3hj8dzHURNULwK3v0+vB3+tZ6eIAjCgojAWxCEJSvWzCZ/fGBegXc0GuWtt94iErlfyeL27dtcvHiRkydP4vUurqzfauiKjQC59BC3qhHT03njKUPHodjY4auZtbPmg5yKjV9vPsjp8dtcDg+RNLNU2T0cDDSyw/dw1Omei1apUfmVGsyUgfn/t3d3z1HUex7HPzOdzGQmyWTyRJ4IDy4BEYiAtet6zhFOJJZVaFgp3K1StiyQUqFqvfNqr/gDUPRGrfKCG7VWOVIrBcbasirA2YOPsAejlIgJcI6ShBAIyeRpMtO9FxTBQJ5IJ79OT96vO6YH+Pitpvtj59fdw46sXItHCALwJYo3ANcS6aEJt/el7n4N+1iOHTs2qnTf0tPTo2PHjqmhoWFa+UxI27fvAMy1QrId547XzztaFSvX5vKV9/xnR6xs/bF0mf54D09DyUTBHEvBHK9TAMD0scYbgGsloYlvcCsOT34D3PXr19XWNv6V87a2Nl2/fv2es5myKHp7+UggEFAsO0el4TwVZEcUy8rR5vIH9HTl6jl7oykAYPZRvAG4ti5epeAYr1q/ZX184aR/xo0bd7+dcDrf8co/Fy2+64BqBYKKWNkqDedNeY07ACBzUbwBuFYYiurJipVjHlDWxaum9OSNSGTydc9T+Y5XFkbj+pfK1YoER6/gK8qO6tnqdcqxWNkHAPMdZwIAM6K2oFILI3F9feWCejSsqBVSbUHFqCUYEykrK1M8Hld3d/eY2wsLC1VWVjaTkWfcA7Fy1eSV6nyiU32ppErCuVoSLRr1Ep20Y+ti3zUNpVMqCedqQc7cvWEUADCzKN4AZkxRKKoNRUsVjUan9fs3bNigxsZGDQ+PfmFMdna2Hn300ZmIOOuyg9a4Txv5/kab/qfjnK4MJdSfHpYjR/lZYdUvWKGNpffJCvBDSADIZBRvAHNGeXm5tm7dqu+++27Uc7xra2sVj8c9TufOz4mr+u/L36sr2aeUc/sJKL2pIR1p+0FXBnv0b9Xrbr+6HgCQcSjeAOaUeDyuDRs2eB1jxv2l64L608lRpfuWYSets71X9HPiqpbnl3qQDgBgAj/XBIBZlrRT+mXghgbSw+N+Z8hO6YeedoOpAACmUbwBYNbdXD5iO86E3xi0xy/mAAD/o3gDwCwLBS0tjhZO+PKcsJWl8nDMYCoAgGkUbwAw4A/FS5WXFRpzWyhoKWqFtC5eZTjV/JF2bPUODylpp72OAmAe4+ZKADBgSW6Rnqt+SB/98ld1DPWOfJ4TzFZxKKqtlWsUD83dFwT5Vcq29eeuVv21+1f1p4dlBQK6P2+B6hbUqCA7x+t4AOYZijcAGLI8v1T/eX+9furt1NneDlkKqCIS05qCCkWsbK/jZRzHcfSnX8+opa9r5LO04+iH3g79faBbOxb/k/Kzwx4mBDDfULwBwKBgIKD7Ywt0f2yB11EyXmtf16jS/Vs9qSF9de2S6suWG04FYD6bV8U7lUrp6NGjam1t1cDAgAoLC1VfX6+amhqvowEAZtjZno6Jt/d2ULwBGDWvirdt24rFYtqxY4cKCgp0/vx5HTx4UHv27FFhYaHX8QAAM2iyGymTdspQEgC4aV4V71AopLq6upFfr1ixQvF4XG1tbSPFu6enR4lEYtTvy8vLUyzmj8d8BXjdtGvM0B3m5x4zdOfW/CojMf2YuDLu9ypzCkxF8p1M2gcTqSHZjqP8rLCx/65Mmh9m1rwq3ndKJBLq6upSaentVzSfOnVKx48fH/W9jRs3jirsc1kkwlMR3GKG7jA/95ihO7fmtzZepZNdFzU4zpXth4sWmYzlK5mwD7b2delEZ4t+HeyRJBVlR/W74iV6MF456393JswPsyPgOBO8Si2DpdNpvffeeyoqKlJDQ8PI536/4j0wMMA/eJeYoTvMzz1m6M5v5/dLf7f+9Ot36ksnR7ZbgYA2ldboHyne4/L7PvhTb6c+/vWM7DG2PVa6TI8UL5nVv9/v88Psyagr3gcOHNClS5fG3FZdXa1du3ZJurnW+9ChQ7IsS5s3bx71vVgs5puSPZZ5+v9RM4oZusP83GOG7vx2fgujcf3HP/xBP/Z26GqyT1ErpFWxcuWO8zIj3OT3fbCp8/yYpVuS/vfqBa2PL1TYmr0K5Pf5YfZkVPHeuXPnpN9xHEeHDx9WX1+ftm/fLssa/xXOAAD/ywoGtbqgwusYMOTKYEJXk/3jbk86af3cd1WrYuUGUwE3zbtXxh85ckSdnZ169tlnlZ3NCysAAMgkw87ET7ORpOFJnngDzJaMuuI9me7ubp06dUqWZWnfvn0jnzc0NKi2ttbDZAAAYCaUhnMVCloTPk6yKsITbeCNeVW84/G49u7d63UMAAAwS0LBLK2LV+mra38bc/t9ucUqDecZTgXcNO+WmgAAgMxWV7pMa8ZYw70oEtfTlas9SATcNK+ueAMAgMxnBYLaUrlavyteqvOJTqUdR0uihVoYjXsdDfMcxRsAAGSkknCuSsK5XscARrDUBAAAADCA4g0AAAAYQPEGAAAADKB4AwAAAAZQvAEAyACDg4O6cuWKenp6vI4CYBw81QQAAB9LJpM6efKkWlpalE7ffFtjWVmZfv/736ukpMTjdAB+iyveAAD4lOM4amxs1E8//TRSuiWpo6NDR44cUXd3t4fpANyJ4g0AgE9dvHhRHR0dY25LJpM6c+aM4UQAJkLxBgDApy5dujTh9osXL5oJAmBKKN4AAPjUb5eXjMW2bUNJAEwFxRsAAJ+qrKx0tR2AWRRvAAB8qqamRnl5eWNuCwQCqq2tNZwIwEQo3gAA+FRWVpaefPJJFRcXj/o8JydHjz32mCoqKjxKBmAsPMcbAAAfKygo0LZt29TW1qbr168rEolo0aJFsizL62gA7kDxBgAgA1RUVHCFG5jjWGoCAAAAGEDxBgAAAAygeAMAAAAGULwBAAAAAyjeAAAAgAEUbwAAAMAAijcAAABgAMUbAAAAMIDiDQAAABhA8QYAAAAMoHgDAAAABlC8AQAAAAMo3gAAAIABFG8AAADAAIo3AAAAYADFGwAAADAgy+sAAAC41ZdK6sfeDg3aKRUqpJWRiAKBgNexAGAUijcAwNf+cvWC/tzVqrTjSJJs21bZjb/pXxc+qMJQ1ON0AHAbS00AAL7VfKNNx662jJTuWzqTffqvv/+f7Ds+BwAvUbwBAL711bVL4267Njygc71XDKYBgIlRvAEAvpS0U+oYSkz4nV8GbhhKAwCTY433FAwODsq2ba9jTEk6nVZ/f7/XMXyNGbrD/NxjhlOTcmzJtnXX0dlxRo7ZTirFLKeBfdAdL+YXjXI/gx9QvKcgJyfH6whT1t/fzz8+l5ihO8zPPWY4dStiZTqX6Bz1mW3bCgZv/kC3trha0Rxmea/YB91hfhgPS00AAL71aMl9CgWtMbetyi9TeU6+4UQAMD6KNwDAt8py8vXv1Q9pabRIt57aHQ1m69HipdpSudrTbABwJ5aaAAB8rSIS03OL1qsvldSQnVL2sK383DyvYwHAXbjiDQDICLlZIRWForICnNoAzE0cnQAAAAADKN4AAACAARRvAAAAwACKNwAAAGAAxRsAAAAwgOINAAAAGEDxBgAAAAygeAMAAAAGULwBAAAAAyjeAAAAgAEUbwAAAMAAijcAAABgAMUbAAAAMIDiDQAAABhA8QYAAAAMoHgDAAAABlC8AQAAAAMo3gAAAIABFO970NPTo6amJvX09HgdZVzRaNTrCBNihu4wP/eYoTvMzz1m6A7zg59RvO9BIpHQ8ePHlUgkvI7iW8zQHebnHjN0h/m5xwzdYX7wM4o3AAAAYADFGwAAADCA4g0AAAAYYO3du3ev1yH8wnEchUIhLVmyROFw2Os4vsQM3WF+7jFDd5ife8zQHeYHPws4juN4HQIAAADIdFleB/Cz5uZmHT9+XDdu3FBeXp6efvppLV682OtYvtLV1aW33npLDzzwgLZt2+Z1HN9IpVI6evSoWltbNTAwoMLCQtXX16umpsbraHNaf3+/Dh8+rJaWFkWjUW3atEm1tbVex/IF9rmZw3HPHc698DOK9zS1tLTo888/1zPPPKOqqioeazRNR48eVVVVldcxfMe2bcViMe3YsUMFBQU6f/68Dh48qD179qiwsNDreHPWp59+Ksuy9Oqrr6q9vV0ffPCBysvLtWDBAq+jzXnsczOH4970ce6F33Fz5TQ1NTVp48aNqq6uVjAYVCwWUywW8zqWrzQ3NysnJ0dLly71OorvhEIh1dXVqbCwUMFgUCtWrFA8HldbW5vX0easZDKps2fPqq6uTuFwWIsXL9aKFSt05swZr6P5AvvczOC45w7nXvgdxXsabNvW5cuX1dfXpzfffFOvvfaajh49quHhYa+j+cbg4KCampr0xBNPeB0lIyQSCXV1dam0tNTrKHNWV1eXgsGgSkpKRj4rKytTZ2enh6n8i33u3nHcc4dzLzIBxXsaEomEbNvW2bNn9cILL2j37t1qb2/XiRMnvI7mG01NTVq/fr0KCgq8juJ76XRaH3/8sdauXUsJmkAymbzrCQg5OTkaGhryKJF/sc9ND8c9dzj3IhOwxnsMBw4c0KVLl8bcVl1dreeee06S9PDDDys/P1+S9Mgjj+jEiRPatGmTsZxz1WTz27x5s1pbW/Xyyy8bTuYfk81w165dkm5eATp06JAsy9LmzZtNRvSdUCh0V8keGhricWT3iH1uetra2jjuuZSdnS2Jcy/8jeI9hp07d076HdaUjW+y+X3xxRfq7u7W/v37Jd28Euk4jt555x3t3r3bRMQ5byr7oOM4Onz4sPr6+rR9+3ZZlmUgmX8VFxfLtm11dXWpuLhYktTe3s4V23vAPjd9Fy9e5LjnUiQS4dwL36N4T9PatWv19ddfa9myZbIsS19++aWWL1/udSxfeOihh7R69eqRX588eVLd3d166qmnPEzlP0eOHFFnZ6eef/75kStBGF8oFNLKlSvV1NSkLVu2qL29XefOnRv56QEmxz43fRz3ZgbnXvgdL9CZpnQ6rcbGRjU3NysrK0urVq3S448/zsloGpqamnTt2jWeZ3sPuru79cYbb8iyLAWDt2/VaGho4LnUE+jv79cnn3yi1tZWRSIR1dfXM68pYp+bWRz3podzL/yO4g0AAAAYwFNNAAAAAAMo3gAAAIABFG8AAADAAIo3AAAAYADFGwAAADCA4g0AAAAYQPEGAAAADKB4AwAAAAZQvAEAAAADKN4AAACAARRvAAAAwACKNwAAAGAAxRsAAAAwgOINAAAAGEDxBgAAAAygeAMAAAAGULwBAAAAAyjeAAAAgAEUbwAAAMAAijcAAABgAMUbAHyopaVFRUVFOn36tCTp8uXLKi0t1bFjx7wNBgAYV8BxHMfrEACAe/fuu+9q//79+vbbb7V161atWbNG+/bt8zoWAGAcFG8A8LEtW7bowoULCgQC+uabbxQOh72OBAAYB0tNAMDHXnzxRX3//fd65ZVXKN0AMMdxxRsAfCqRSOjBBx9UXV2dGhsb1dzcrKKiIq9jAQDGQfEGAJ/atWuXEomEPvzwQ7300kvq7u7WRx995HUsAMA4WGoCAD70ySef6LPPPtPbb78tSXr99dd1+vRpvf/++x4nAwCMhyveAAAAgAFc8QYAAAAMoHgDAAAABlC8AQAAAAMo3gAAAIABFG8AAADAAIo3AAAAYADFGwAAADCA4g0AAAAY8P/AuiSW1dPIrgAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "date_data = result_to_plot.loc[result_to_plot['variable']=='LC']\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y',color = 'value'), data = date_data)+geom_point(size =75, alpha = 0.8)+theme_bw()+scale_color_manual(values = ['grey','brown','orange','mediumaquamarine','royalblue','orchid'])+ggtitle('LC')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# take a closer look at each\n", - "date_data = result_to_plot.loc[result_to_plot['variable']=='shortdate']\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y',color = 'value'), data = date_data)+geom_point(size =75, alpha = 0.8)+theme_bw()+scale_color_manual(values = ['grey','brown','mediumaquamarine','mediumaquamarine','royalblue','orchid'])+ggtitle('DATE')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/tzx804/env/fixjupyter/lib/python3.7/site-packages/ipykernel_launcher.py:4: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", - " after removing the cwd from sys.path.\n" - ] - }, - { - "data": { - "image/png": "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1cGDByVJvr6+kqR169apV69eGj58uCIjIzVmzBhdPAfw1VdfKTIyUp07d9bUqVN16623SpKmT5+uiRMnqlevXmrdurXeeOMNq+ZFixZZx5s8ebKKi4tVXFysCRMmqEOHDoqJidGrr74qSXrjjTfUvn17xcbGatSoUVXTVBfDPS4AAAC4Lhw6dEgff/yx3nnnHd1www368MMP9d133ykxMVEvvPCChgwZYm373HPPaeXKlQoJCVF6erok6a233tKf/vQnjRkzRgUFBSouLi5xjO3bt2vPnj0KDg7WTTfdpO+//15dunTR5MmTtWHDBoWFhWn06NEO++zfv19r165VVlaW2rVrp/vvv1+HDh3SkiVL9P3338vT01MPPPCAPvjgA0VHRyslJUW7d++WJKu2l156SUeOHFGdOnWssdqGMy4AAAC4LoSFhSkmJkZubm6Kjo5Wnz59ZLPZFBMTo6SkJIdtb7rpJk2YMEFvv/22FVC6d++uF154QTNnztTRo0dVt27Jd0p17dpVoaGhcnNzU3x8vJKSkrR//361bt1aYWFhklQiuAwePFh16tRRo0aNFBQUpFOnTunbb7/V1q1bdcMNNyg+Pl7ffvutDh8+rNatW+vw4cP64x//qBUrVsjf31+SFBsbqzFjxmjRokXy8Kid5x4ILgAAALgu1KlTx/q1m5ub9b2bm5uKiooctn3rrbf0/PPP6/jx4+rcubPOnj2ru+++W4mJiapbt64GDRqkNWvWlHsMd3f3Euterq6L+xhjNH78eO3YsUM7duzQzz//rOnTpyswMFA//fSTevXqpbfeekuTJk2SJH355Zd68MEHtW3bNt1www0VOu71huACAACAWueXX35Rt27d9Nxzz6lx48Y6fvy4dcZj6tSpuuOOO7Rz584KrdWuXTsdPnzYOquzZMmSy+7Tp08fffLJJzp9+rQk6dy5czp69KhSU1Nlt9t155136vnnn9e2bdtkt9t1/Phx9e7dWzNnzlRGRoays7Ov+LPXVLXzPBMAAABqtccee0wHDx6UMUZ9+vRRXFycZs6cqffff1+enp5q2rSpnnzyyQqtVbduXc2ZM0cDBgxQvXr1dMMNN1x2n/bt2+v5559Xv379ZLfb5enpqX/84x+qW7eu7rnnHtntdknSiy++qOLiYv3ud79TRkaGjDGaOnWqAgICnPr8NRGPQ77O8AhG59FD59A/59FD59A/59FD59C/2ik7O1u+vr4yxujBBx9URESEHn744eou67rCpWIAAACAk95++23Fx8crOjpaGRkZmjx5cnWXdN3hjMt1hp/yOI8eOof+OY8eOof+OY8eOof+AdcGZ1wAAAAAuDyCCwAAAACXR3ABAAAA4PIILgAAAABcHsEFAAAANd7EiRMVFBSkDh06WGPnzp1T3759FRERob59+yotLa3UfadNm6bo6GhFRUVp6tSpMsYoNzdXgwcPVmRkpKKjo/XEE0847LN06VK1b99e0dHRuvvuux3mMjMzFRoaqilTplhjixcvVkxMjGJjYzVgwAClpqZac2+++aZ1nGnTpkmSvvnmG3Xu3FkxMTHq3Lmz1qxZI0nl1rVgwQI1btxY8fHxio+P17x58yRJO3bsUPfu3RUdHa3Y2FiHF2SOGTNG7dq1U4cOHTRx4kQVFhZKktLS0jR06FDFxsaqa9eu2r17t7VPq1atFBMTo/j4eHXp0sUa37FjhxISEqzxzZs3l/dbVnkG15WcnJzqLqHGo4fOoX/Oo4fOoX/Oo4fOoX/VY/369Wbr1q0mOjraGnvsscfMiy++aIwx5sUXXzTTpk0rsd/3339vbrzxRlNUVGSKiopMQkKCWbt2rcnJyTFr1qwxxhiTn59vevToYb766itjjDEHDhww8fHx5ty5c8YYY06dOuWw5tSpU83o0aPNgw8+aIwxprCw0DRu3NicOXPGquuZZ54xxhizZs0a06dPH5OXl+ew1rZt20xKSooxxphdu3aZ4OBgY4wpt653333XOualfv75Z3PgwAFjjDEpKSmmadOmJi0tzRhjzJdffmnsdrux2+1m1KhRZs6cOcYYYx599FEzffp0Y4wx+/btM7/5zW+s9Vq2bGl9lkv17dvXquXLL780t9xyS4ltnOFxdWMQAAAAaivb56uv+THMkN+WOt6zZ08lJSU5jC1fvlzr1q2TJI0fP169evXSzJkzHbax2WzKy8tTQUGBjDEqLCxUkyZN5OPjo969e0uSvLy81KlTJyUnJ0u68M6WBx98UIGBgZKkoKAga72tW7fq1KlTGjBggLZs2XKhZmNkjFFOTo4aNmyozMxMhYeHS5Lmzp2rJ554QnXq1HFYq2PHjtaa0dHROn/+vPLz88utqyxt27a1fh0cHKygoCCdOXNGAQEBGjRokDXXtWtXa629e/daZ3MiIyOVlJSkU6dOqUmTJmUex2azKTMzU5KUkZGh4ODgcuuqLC4VAwAAwHXp1KlTatasmSSpadOmOnXqVIltunfvrt69e6tZs2Zq1qyZ+vfvr6ioKIdt0tPT9c9//lN9+vSRJB04cEAHDhzQTTfdpISEBK1YsUKSZLfb9ec//1mzZs1y2N/T01Nz585VTEyMgoODtXfvXt17773WWhs3blS3bt10yy236McffyxR47Jly9SpUycr3JRV18VtY2NjNXz4cB0/frzEWps3b1ZBQYHatGnjMF5YWKj3339fAwYMkCTFxcXp008/tfY5evSoFWpsNpv69eunzp0763//93+tNV577TU99thjat68uR599FG9+OKLJY7vjFoXXIqKirR8+XK9+uqreuGFFzR37lwdPHiwussCAADANWSz2WSz2UqMHzp0SPv27VNycrJSUlK0Zs0abdy40ZovKirS6NGjNXXqVLVu3doaO3jwoNatW6fFixfrvvvuU3p6uubMmaNBgwYpNDTU4RiFhYWaO3eutm/frhMnTig2Ntb6R31RUZHOnTunH374Qf/93/+tESNGyFzyfvg9e/bo8ccf1//8z/84rFlaXbfddpuSkpK0c+dO9e3bV+PHj3fY5+TJkxo7dqzeffddubk5xoAHHnhAPXv21M033yxJeuKJJ5Senq74+Hi9+eab6tixo9zd3SVJ3333nbZt26avv/5a//jHP7RhwwZJF84evfrqqzp+/LheffVVK5xdLbXuUjG73S5/f39NmDBB9evX18GDB/Xxxx/r/vvvt073AQAAoOZr0qSJTp48qWbNmunkyZMOl3Rd9NlnnykhIUG+vr6SpIEDB2rTpk3WP+B///vfKyIiQg899JC1T2hoqLp16yZPT0+FhYWpbdu2OnjwoDZt2qSNGzdqzpw5ys7OVkFBgXx9fXXnnXdKknWWY8SIEXrppZestYYNGyabzaauXbvKzc1Nqampaty4sZKTkzV06FC99957Jc6QlFZXw4YNrV9PmjTJutFfuvDAgMGDB2vGjBlKSEhwWOvZZ5/VmTNnHMKRv7+/3n33XUkXLnULCwuzAlJISIikC5e1DR06VJs3b1bPnj21cOFCvf7665Kku+66S5MmTbrM71Dl1LozLl5eXurdu7cCAwPl5uamdu3aKSAgQCdPnpR04Tf1xIkTDl8Xr9WrCUr7SQIqhx46h/45jx46h/45jx46h/65jttvv10LFy6UJC1cuFB33HFHiW1atGih9evXq6ioSIWFhVq/fr11qdhf/vIXZWRk6LXXXnPYZ8iQIda9M6mpqTpw4IBat26tDz74QMeOHVNSUpJmzZqlcePG6aWXXlJISIj27t2rM2fOSLrwxLCLxxgyZIjWrl0r6cJlYwUFBWrUqJHS09M1ePBgvfTSS7rpppscjl9WXRf/PStJiYmJ1jEKCgo0dOhQjRs3TsOHD3fYZ968eVq5cqUWL17scBYmPT1dBQUF1jY9e+dERtUAACAASURBVPaUv7+/cnJylJWVJUnKycnRqlWrrCe5BQcHa/369ZKkNWvWKCIioozfmStjM5eei6qFsrOz9eqrr+oPf/iDGjdurLVr11oNv+iWW26xboICAACA6xk9erTWrVun1NRUNWnSRM8++6yGDBmiESNG6NixY2rZsqWWLl2qBg0aaMuWLXrrrbc0b948FRcX64EHHtCGDRtks9k0YMAA/f3vf1dycrKaN2+uyMhI696SKVOmaNKkSTLG6M9//rNWrFghd3d3PfXUUxo1apRDPQsWLNCWLVs0e/ZsSdJbb72l119/XZ6enmrZsqUWLFighg0bqqCgQBMnTtSOHTvk5eWlWbNm6Te/+Y2ef/55vfjiiw7/+F+1apUKCgrKrOu//uu/lJiYKA8PDzVo0EBz585VZGSkFi1apHvuuUfR0dEO9cXHx8vDw0MtW7aUn5+fJGnYsGH661//qk2bNmn8+PGy2WyKjo7W/PnzFRgYqMOHD2vo0KGSLlyudvfdd+upp56SdOESsj/96U8qKiqSt7e35syZo86dO1+13+NaHVyKi4u1aNEiNWjQQLfddpukC2dcsrOzHbbz9fWVv79/dZRYaefPn1fdunWru4wajR46h/45jx46h/45jx46h/4B10atu8flIrvdrk8//VTu7u4Oj4Hz9/evMSGlNLU4h1419NA59M959NA59M959NA59A+4NmrdPS7ShT9QEhMTlZOTo5EjR1pPSAAAAADgmmplcPniiy905swZjR49Wp6entVdDgAAAIDLqHWXiqWnp2vr1q1yd3d3eDnQbbfdptjY2GqsDAAAAEBZavXN+dej3Nxc+fj4VHcZNRo9dA79cx49dA79cx49dA79A66N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UBEREYqIiNDChQut8cWLFysmJkaxsbEaMGCA9blGjhxprd+qVSvFxzue4Tt27Jh8fX01a9Ysa+zVV19VdHS0OnTooNGjRysv78JLhmfPnq3w8PASfcvIyNBtt92muLg4RUdHW++KWbt2rcNn9/b21ueffy7pwsNcnnrqKbVt21ZRUVF64403Sv19uJwKv8dl+PDhWrlypXr27Klx48ZpyJAhqlPnPz+Bs9vtql+/vrKysq6oEFwdvL/AefTQObW9f5kFeZqy6bNyt7m9RXsNDyv7Ma+1vYfOon/Oo4fOoX/VY8OGDfL19dW4ceO0e/dua/z48eOaNGmS9u/fr61bt6pRI8fHcH/55Zd67bXX9PXXXys/P1+9evXSt99+K39/f2VmZsrf31+S9MgjjygoKMh66WNWVpYGDx6sgoICzZ49W126dHFYd9euXRoyZIh++eXCAxl69eqlWbNmldguKSlJmZmZmjVrlm6//XYNHz5cknTu3Dl16dJFW7Zskc1mU+fOnbV161b5+fkpODhYe/fuVaNGjTRt2jT5+Pho+vTpDuv++c9/Vv369fXXv/7VGhs+fLhsNpu6deumRx99VCkpKerRo4f27t2runXrasSIERo0aJAmTJig7du3KzAwUL169dKWLVusvr3wwgvKyMjQzJkzdebMGbVr106//vqrvLz+c6bx3LlzCg8PV3JysvUizLVr12rBggVyc3PT6dOnFRQUpMqq8M35CQkJmj17tpo2bVrqvJubm06dOlXpAgDgeuLv5a2QevWVkpNR5jZRATXxTeAAcHlByz++5sc4fcddpY737NlTSUlJJcYffvhhvfzyy7rjjjtK3W/v3r3q2bOnPDw85OHhodjYWK1YsUIjRoywQosxRufPn7feaC9JTz/9tB5//HH993//d6nrLl68WKNGjbrs52nVqpUklXigw8qVK9W3b181aNBAktS3b1+tWLFCw4cPlzFGOTk5atiwoTIzMxUeHu6wrzFGS5cu1Zo1a6yxzz//XGFhYapXr57DtkVFRTp//rw8PT2Vm5ur4OBgSVLHjh1LrddmsykrK0vGGGVnZ6tBgwby8HCMFJ988okGDhxoBfi5c+fqww8/tD7jlYQWqRKXij366KNlhpaL+OkCAEi3No8qcy7Mr4HaE1wAoEosX75cISEhiosr+yx3XFycVqxYodzcXKWm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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# look at missing values\n", - "miss = x_50_before.T.isnull().sum().astype(float).tolist()\n", - "date_data = result_to_plot.loc[result_to_plot['variable']=='shortdate']\n", - "date_data['missingness']=[(mis/x_50_before.shape[1])*100 for mis in miss]\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y', color='missingness'),data = date_data)+geom_point(size =75, alpha = 0.8) + scale_color_gradient(low = \"#00AFBB\", high = \"#E7B800\")+theme_bw()+ggtitle('MISSINGNESS')" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(177, 232)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/tzx804/env/fixjupyter/lib/python3.7/site-packages/ipykernel_launcher.py:10: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", - " # Remove the CWD from sys.path while we load stuff.\n" - ] - } - ], - "source": [ - "# grouping according to missing values! --> look at x_90\n", - "\n", - "x_90_before = coverage(x.loc[labels['datetime']<'2019-06-01',:], 0.9,0.9)\n", - "print(x_90_before.shape)\n", - "data_before_pca = log_z_zeroone_na(x_90_before)\n", - "result, args = runPCA(data_before_pca)\n", - "result.set_index(x_90_before.index, inplace = True)\n", - "\n", - "info = labels[['index','MS_instrument', 'LC','ColumnLength','shortdate']] # i have not included pid because there are so many different..\n", - "info['ColumnLength'] = labels.ColumnLength.astype(int).astype(str)\n", - "info = info.loc[x_90_before.index,:]\n", - "result_to_plot = pd.merge(result,info, left_index = True, right_index = True)\n", - "result_to_plot = pd.melt(result_to_plot, id_vars =['index','x','y'], value_vars =['MS_instrument','LC','ColumnLength','shortdate']) " - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/tzx804/env/fixjupyter/lib/python3.7/site-packages/ipykernel_launcher.py:4: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", - " after removing the cwd from sys.path.\n" - ] - }, - { - "data": { - "image/png": "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Tzyh+++/X6tWrdIjjzyiV155RU8++aS+853v6PLLL4+f+61vfUt/+ctfVFxcrJaW7g8a7733Xn3+85/X1VdfrXA4rFgfm/i89dZbevvttzVx4kStXr1ar776qs444wzdeOONeumllzR9+nR97GMfsz1mz549ev7559Xe3q65c+fqM5/5jA4cOKDHHntMr776qpKSkvTZz35WDz/8sBYuXKjKykrt3LlTkuJ9u/vuu3X48GH5fL74MQyMER0kTNga+CaskVF2k9ae7jtcoscrKmx9jFqm/lBZpZ8dONjv4xpOMOpTFzrxqNDJumFasUF/edAAACAASURBVL63cLZWZGbI73Yr3+vVtZMn6IEVC5Xn8w7b8w7GoxU1ag73PbpnylJrJKo/nCAkAgAwffp0LV68WC6XSwsXLtSFF14owzC0ePFilZSU2M5dvXq11q5dq/vuuy8eaM455xx95zvf0bp161RaWiq/39/rOc4880xNmjRJLpdLy5YtU0lJifbs2aMZM2Zo+vTpktQr6FxyySXy+XzKy8tTQUGBamtr9dxzz2nz5s1atWqVli1bpueee06HDh3SjBkzdOjQIf37v/+7/vznPysjo/t+d0uWLNHVV1+t9evXy+NhrGIwCDpImJWZA9+ocmXW6LyRZWc0qt9VVvbbvrG6Wq39TMmb7E8e8NpTTtB+Mra1tOrW7Tu05sWXdOeut5XriemXS+fomXOX6/MzpyjHO/D6nZGwpz2gyAD3Lg7GTFV0BUewRwCAscjn88X/3+Vyxb92uVyKHrf76L333qu77rpL5eXlWrlypRobG/Xxj39cTz75pPx+vy6++GL9/e9/H/A53G53r+ueqF9HH2NZlq6//npt3bpVW7du1d69e3X77bcrOztb27Zt0wUXXKB7771XN9xwgyTpqaee0k033aQtW7Zo1apVg3re8Y6gg4S5enKRPP1M8cr0eHT5hNE5bW1nW5uCfQxlHxUxTW1vae2z7cqJBQNe+4oe7c/VN+mTW97W2S9u0oWvbNb39pcMecTnpfoG/ce2bXqjqUkxy1LMMvVqY6M+t3Wb/tk88NTBkZTmcff7syBJLsNQUY9/JAAAOFUHDx7UWWedpW9961vKz89XeXl5fETl5ptv1gc+8AFt3759UNeaO3euDh06FB81euyxx074mAsvvFC//e1vVVfXfYuHpqYm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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# look at missing values\n", - "miss = x_90_before.T.isnull().sum().astype(float).tolist()\n", - "date_data = result_to_plot.loc[result_to_plot['variable']=='shortdate']\n", - "date_data['missingness']=[(mis/x_90_before.shape[1]) for mis in miss]\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y', color='missingness'),data = date_data)+geom_point(size =75, alpha = 0.8) + scale_color_gradient(low = \"#00AFBB\", high = \"#E7B800\")+theme_bw()+ggtitle('MISSINGNESS')" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAtoAAAIhCAYAAABwux3pAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdd3gc5b0v8O/M9iJp1SWrulu2wZYLxjZgDJgWh16TUA55uKHkJCGQyiFADslNOZBTCE9yk5NLuGB8iAkllBgIrtjYWO6We5OsrpVW23dnZ+b+IXvX492VLdujVfl+nsfP431nNPvTzyv5u7PvvCOoqqqCiIiIiIjOKzHTBRARERERDUcM2kREREREOmDQJiIiIiLSAYM2EREREZEOGLSJiIiIiHTAoE1EREREpAMGbSIiIiIiHTBoE9GItWTJEsyaNQtOpxOlpaW47rrrsHbt2vj2+vp63HDDDcjJyUFWVhYWLlyIdevWxbcfOXIEgiAgFoslHfv+++/Hv/zLv2jGTt2/uroaZrMZnZ2dmv1qa2shCAKOHDkSP5YgCNi4cWN8nwMHDkAQhLTfW3V1NT755JOk8ZUrV0IURTidTs2f9evXAwAuv/xyWK1WNDY2xr/mk08+QXV1teY4S5cuxZw5c+BwOFBUVIQ5c+bgpZdegqqquO666+LHNZlMMJvN8ccPPfQQVq5cifLy8qTaLr/8cvzxj39M+z0REQ01DNpENCK98MIL+M53voMf//jHaGtrQ0NDAx555BG88847AICDBw9i/vz5uOCCC3D48GE0Nzfj5ptvxtVXXx0PpefD6NGj8frrr8cf79ixA8FgMGm/vLy8pOB+tkaNGgW/36/5M3fu3Ph2h8OBf/3Xf0379c8//zy+/e1v43vf+x5aW1vR1taG3/3ud/jss88QjUbx4Ycfxo/71a9+Fd///vfjj3/3u9+dl++BiGgoYNAmohGnp6cHP/nJT/Db3/4Wt9xyCxwOB0wmE7785S/j17/+NQDgmWeewdy5c/Gzn/0MeXl5yMrKwre+9S3cc889+MEPfnDearnnnnvwyiuvxB//+c9/xr333pu033333Yft27dj1apV5+250/nWt76F119/HQcPHkzadqJ3L730Em677TZkZWVBEATU1tbitddeg8Vi0b0+IqKhgkGbiEac9evXIxwO4+abb067z8cff4zbb789afyOO+7AZ599hlAodF5qufjii+H1erF7927IsoylS5fia1/7WtJ+drsdP/7xj/Hkk0+el+ftS1lZGR588EE8/fTTSdvWr1+PSCSCG2+8Ufc6iIiGOgZtIhpx3G43CgoKYDQa0+7T2dmJ0tLSpPHS0lIoioKurq7zVs+Js9off/wxampqUFZWlnK/b3zjG2hoaMCHH354Ts/X3NwMl8ul+RMIBDT7/OhHP8Lf/vY37Nq1SzPe2dmZ1Lt58+bB5XLBZrNh9erVZ13DyfPjiYiGAwZtIhpx8vPz0dnZmfIixhMKCgrQ0tKSNN7S0gJRFJGbm9vncxiNRkiSpBmTJAmiKEIUtb9677nnHixZsgQvv/xyymkjJ1gsFjz11FN46qmn+nzu0xk1ahQ8Ho/mj8Ph0OxTWFiIb37zm/jJT36iGU/Vu3Xr1sHj8SA/Px+Kopx1DZdccsk5fV9ERIMNgzYRjThz586FxWLB22+/nXafq666Cn/5y1+Sxt944w3MnTsXdru9z+eorKyMrxpywuHDh1FRUZEUtKuqqjB69Gh88MEHuOWWW/o87j/90z/B4/Hgr3/9a5/7nQ/f+973sGLFCtTV1cXHTvTuxEWjRESUHoM2EY04OTk5+OlPf4pHH30Ub7/9NoLBICRJwocffojvf//7AICnn34a69atw5NPPomuri74fD7813/9F1555RX88pe/1BwvEokgHA7H/yiKgltvvRXvv/8+PvroI8iyjObmZjz33HO46667Utb03//93/j000+Tziyfymg04tlnn02qIRVJkjR19XUGPxWXy4XHH38cv/rVrzRjTz/9NB555BEsW7YMPp8PiqJg69atSdNPiIhGOgZtIhqRHn/8cbzwwgt47rnnUFhYiIqKCrz44ou46aabAADjx4/H2rVrsW3bNlRXV6O0tBRvvvkmli9fjvnz52uO5XQ6YbPZ4n8+/fRTTJkyBa+//jp+9KMfIS8vD3PnzsWcOXNSXmAIAGPHjsWsWbPOqPa777475fzxU11//fWaup555hkAvfOjT11H+80330x5jG9/+9swGAyase9///t44YUX8Ktf/QrFxcUoLi7GN77xDfzyl7/EvHnzzuh7ICIaCQRVVdVMF0FERERENNzwjDYRERERkQ4YtImIiIiIdMCgTURERESkAwZtIiIiIiIdMGgTEREREemAQZuIiIiISAcM2kREREREOmDQJiIiIiLSAYM2EREREZEOGLSJiIiIiHTAoE1EREREpAMGbSIiIiIiHTBoExERERHpgEGbiIiIiEgHDNpERERERDpg0CYiIiIi0gGDNhERERGRDhi0iYiIiIh0wKBNRERERKQDBm0iIiIiIh0waBMRERER6YBBm4iIiIhIBwzaREREREQ6YNAmIiIiItIBgzYRERERkQ4YtImIiIiIdMCgTURERESkAwZtIiIiIiIdMGgTEREREemAQZuIiIiISAcM2kREREREOmDQJiIiIiLSAYM2EREREZEOGLSJiIiIiHTAoE1EREREpAMGbSIiIiIiHTBoExERERHpgEGbiIiIiEgHDNpERERERDpg0B7CwuFwpksYVNgPLfYjgb3QYj+02I8E9kKL/aBzxaA9hCmKkukSBhX2Q4v9SGAvtNgPLfYjgb3QYj/oXDFoExERERHpgEGbiIiIiEgHDNpERERERDpg0CYiIiIi0gGDNhERERGRDhi0iYiIiIh0wKBNRERERKQDBm0iIiIiIh0waBMRERER6YBBm4iIiIhIBwzaREREREQ6YNAmIiIiItIBgzYRERERkQ4YtImIiIiIdMCgTURERESkAwZtIgCqomS6BCIiIhpmjJkugCiTOrdvx/6lS9Fz4ADMOTmouvZajLn5Zggi34MSERHRuWHQphGre+9e1P385/Gz2dGeHuz/n/+B5Pdj0n33Zbg6IiIiGup42o5GrMPvvptyykjDRx9BCgQyUBERERENJwzaNGL5jx1LOa5IEkIdHQNcDREREQ03DNo0YjnLylKOiyYTbIWFA1wNERERDTcM2jRijb7hhpQXPVYsWgSTw5GBioiIiGg4YdCmESt30iTM+MEPkD1mDADAnJ2Ncbfdhkn33pvhyoiIiGg44KojNKIV1taisLYWiiRBNJkyXQ4RERENIzyjTQQwZBMREdF5x6BNRERERKQDBm0iIiIiIh0waBMRERER6YBBm4iIiIhIBwzaREREREQ6YNAmIiIiItIBgzYRERERkQ4EVVXVTBcx2IXDYSiKkukyksiyDIPBkOkyBg32Q4v9SGAvtNgPLfYjgb3QGkr9sNvtmS6BUmDQHsKCwSB/sE7CfmixHwnshRb7ocV+JLAXWuwHnStOHSEiIiIi0gGDNhER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Ti9fvhxPPvlkVqhOJpMz/vKePm67rq4O27Ztw5kzZ9JBOxgM3nKi1nximmahmzCvsB5WrEcGa2HFelixHhmshRXrQXdr3gftPXv23PK4oigwDAMjIyMoLS0FAPT396O8vHxWjy8IAn+QiIiIiGjOLfjJkE6nE83NzWhvb4eiKLh69So6Ozuxfv36nOefO3cO8Xgcpmmit7cXhw8fxpo1a/LcaiIiIiJa7OZ9j/Zs7N69G2+//Ta+973vwePxYPfu3ekhIt3d3XjjjTfwyiuvAAA+/fRTvP3229A0DcFgEA8++CA2bNhQyOYTERER0SIkmBw3sWDFYjF4vd5CN2PeYD2sWI8M1sKK9bBiPTJYCyvWg+7Wgh86QkREREQ0HzFoExERERHZgEGbiIiIiMgGDNpERERERDZg0CYiIiIisgGDNhERERGRDRi0iYiIiIhswKBNRERERGQDBm0iIiIiIhswaBMRERER2YBBm4iIiIjIBgzaREREREQ2YNAmIiIiIrIBgzYRERERkQ0YtImIiIiIbMCgTURERERkAwZtIiIiIiIbMGgTEREREdmAQZuIiIiIyAYM2kRERERENmDQJiIiIiKyAYM2EREREZENGLSJiIiIiGzAoE1EREREZAMGbSIiIiIiGzBoExERERHZgEGbiIiIiMgGDNpERERERDZg0CYiIiIisgGDNhERERGRDQTTNM1CN2K+SyQSMAyj0M3Ious6JEkqdDPmDdbDivXIYC2sWA8r1iODtbBaSPXwer2FbgLlwKC9gMViMf5gTcN6WLEeGayFFethxXpksBZWrAfdLQ4dISIiIiKyAYM2EREREZENGLSJiIiIiGzAoE1EREREZAMGbSIiIiIiGzBoExERERHZgEGbiIiIiMgGDNpERERERDZg0CYiIiIisgGDNhERERGRDRi0iYiIiIhswKBNRERERGQDBm0iIiIiIhswaBMRERER2YBBm4iIiIjIBgzaREREREQ2YNAmIiIiIrIBgzYRERERkQ0YtImIiIiIbMCgTURERERkAwZtIiIiIiIbMGgTEREREdmAQZuIiIiIyAYM2kRERERENmDQJiIiIiKyAYM2EREREZENGLSJiIiIiGzAoE1EREREZAMGbSIiIiIiGzBoExERERHZgEGbiIiIiMgGDNpERERERDaQC92Au3X48GF0dHRgcHAQra2teO655255/qFDh3Dw4EGoqoqWlhY89dRTkOUFXwYiIiIimmcWfI92IBDAI488go0bN9723AsXLuDgwYN4+eWX8dd//dcYGxtDe3t7HlpJREREREvNgg/aLS0taG5uhsfjue25HR0d2LhxIyoqKuDxeLB9+3Z0dHTkoZVEREREtNQsqTETQ0NDWLNmTfrryspKRKNRxGIxeL1eAEA4HEYkErHcz+/3IxgM5rWtsyEIQqGbMK+wHlasRwZrYcV6WLEeGayFFetBd2tJBW1FUeByudJfu91uAEAymUwH7U8++QT79++33G/79u3YuXNn/ho6S7PpxV9KWA8r1iODtbBiPaxYjwzWwor1oLs1r4P266+/ju7u7pzHli9fjq997Wt39HhOpxPJZDL99dT/p4fvtrY2NDU1We7n9/vv6HnyJR6P801gGtbDivXIYC2sWA8r1iODtbBiPehuzeugvWfPnjl9vPLycgwMDKC1tRUA0N/fD5/Pl+7NBoBgMDgvh4nkYppmoZswr7AeVqxHBmthxXpYsR4ZrIUV60F3a8FPhtR1HaqqwjRNmKYJVVWh63rOc9evX49jx45hcHAQ8XgcBw4cwIYNG/LcYiIiIiJaCuZ1j/ZsHDhwwDKm+uTJk+kx1ePj4/jhD3+Ib37zmygqKkJjYyMefPBB/PjHP06voz0fx14TERER0cInmPxcZMGavloKsR43Yz0yWAsr1sOK9chgLaxYD7pbC37oCBERERHRfMSgTURERERkAwZtIiIiIiIbMGgTEREREdmAQZuIiIiIyAYM2kRERERENmDQJiIiIiKyAYM2EREREZENGLSJiIiIiGzAoE1EREREZAMGbSIiIiIiGzBoExERERHZgEGbiIiIiMgGDNpERERERDaQC90AIiICRkdH0dnZiXg8jurqajQ2NkKW+RZNRLSQ8V2ciKjALl68iPb2dhiGAQC4cOECzpw5g6effhpOp7PArSMios+KQ0eIiApI13V89NFH6ZA9ZWRkBJ9++mmBWkVERHOBQZuIqICGhoYQj8dzHuvp6clza4iIaC4xaBMRFZDD4ZjxGMdoExEtbAzaREQFVFpaipKSkpzHGhsb89waIiKaSwzaREQFtmvXLgQCgfTXgiCgpaWFQZuIaIHj55JERAVWXFyMF198Eb29vYjH46iqqkIoFCp0s4iI6C4xaBMRzQOiKKKurq7QzSAiojnEoSNERERERDZg0CYiIiIisgGDNhERERGRDRi0iYiIiIhswKBNRERERGQDBm0iIiIiIhswaBPRnDFNE0bSgGmYhW4KERFRwXEdbSKaE5GTYUwcnoAe1iD5JATaQghu4aYrRES0dAmmabLr6TYSiQQMwyh0M7Loug5JkgrdjHmD9bDKZz3iZ2OY/MNE1u3+BwPwbvDnpQ23wmvDivWwYj0yWAurhVQPr9db6CZQDuzRngW3213oJuQUi8X4gzUN62GVz3pMnBqFKGaPREueSqD0vnIIopCXdsyE14YV62HFemSwFlasB90tjtEmorumjas5b9cjOkyVH5oREdHSxKBNRHfNUebMebsckiE4C9ubTUREVCgM2kR014LbinLfvjUEQWDQJiKipYlBm4jumrfRh7JnKuCsdEKQBDjKHCh9vAz+dcFCN42IiKhgOBmSiOaEt9EHb6Ov0M0gIiKaN9ijTURERERkAwZtIiIiIiIbMGgTEREREdmAQZuIiIiIyAYM2kRERERENmDQJiIiIiKyAYM2EREREZENGLSJiIiIiGzAoE1EREREZAMGbSIiIiIiGzBoExERERHZgEGbiIiIiMgGDNpERERERDZg0CYiIiIisgGDNhERERGRDRi0iYiIiIhswKBNRERERGQDBm0iIiIiIhswaBMRERER2YBB+w6Fw2G0t7cjHA4Xuinwer2FbgLrcRPWI4O1sGI9rFgPq/lSD9bCivWgu8WgfYcikQj279+PSCRS6KbMC6yHFeuRwVpYsR5WrIcV65HBWlixHgsbgzYRERERkQ0YtImIiIiIbMCgTURERERkA+lv//Zv/7bQjVhITNOE0+lEfX09XC5XoZtTcKyHFeuRwVpYsR5WrIcV65HBWlixHgubYJqmWehGEBEREREtNnKhG7AQHD58GB0dHRgcHERrayuee+65W55/6NAhHDx4EKqqoqWlBU899RRkefGUOhaLYe/evbh48SK8Xi927dqFdevW5Ty3vb0dH3zwASRJSt/2jW98AyUlJflq7pyb7es3TRO/+93vcOzYMQDApk2b8Oijj0IQhHw32VazrcdivBZudifvFYv9fQKYfT2OHz+OvXv3Wl7/l770JTQ0NOSrqbbTNA3vvvsuLl26hHg8juLiYjz66KNobGzMef5ivz7upB5L4fp46623cPny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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# take a closer look at each\n", - "date_data = result_to_plot.loc[result_to_plot['variable']=='ColumnLength']\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y',color = 'value'), data = date_data)+geom_point(size =50, alpha = 0.8)+theme_bw()+scale_color_manual(values = ['grey','brown','mediumaquamarine','mediumaquamarine','orchid'])+ggtitle('COLUMN LENGTH')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAt4AAAIhCAYAAAB5UL2TAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdeXQb530v/O8MdhAEwZ0USZHURmqnREuybMmyLCmWLFlxIsfOdW4T37Y3S91FafO+b9+T09Pbk5ykvW3cZnFv7/uevifN4riO3ES25S22tVgVLcqUtZCSSIoixX0FCBI7MDPvHxBBjgBSJEUOuHw/5+gcY2YA/PwjSHzx4JlnBEVRFBARERER0awSk10AEREREdFiwOBNRERERKQBBm8iIiIiIg0weBMRERERaYDBm4iIiIhIAwzeREREREQaYPAmIiIiItIAgzcR0TxRUlKC999/P2770NAQjh49iqVLl8Jms2H58uU4evQo+vv7k1AlERGNh8GbiGgeC4VC2LNnD+rq6vDOO+9gaGgIVVVVyMzMRHV1dbLLIyKiMfTJLoCIiKbvZz/7GVpbW3Hy5EnYbDYAQE5ODv7qr/4qyZUREdHdOOJNRDSPvf/++9i/f38sdBMR0dzF4E1ENI8NDAwgPz8/2WUQEdEkMHgTEc1jmZmZ6OrqSnYZREQ0CQzeRETz2N69e/Huu+/C6/UmuxQiIroHBm8ionkkHA4jEAjE/v3e7/0eioqKcOTIEdy4cQOyLGNgYADf+9738NZbbyW7XCIiGoPBm4hoHnniiSdgsVhi/77zne/g/fffR3l5Ofbt2we73Y6tW7eiv78f27ZtS3a5REQ0hqAoipLsIoiIiIiIFjqOeBMRERERaYDBm4iIiIhIAwzeREREREQaYPAmIiIiItIAgzcRERERkQYYvImIiIiINMDgTURERESkAQZvIiIiIiINMHgTEREREWmAwZuIiIiISAMM3kREREREGmDwJiIiIiLSAIM3EREREZEGGLyJiIiIiDTA4E1EREREpAEGbyIiIiIiDTB4ExERERFpgMGbiIiIiEgDDN5ERERERBpg8CYiIiIi0gCDNxERERGRBhi8iYiIiIg0wOBNRERERKQBBm8iIiIiIg0weBMRERERaYDBm4iIiIhIAwzeREREREQaYPAmIiIiItIAgzcRERERkQYYvImIiIiINMDgTURERESkAQZvIiIiIiINMHgTEREREWmAwZuIiIiISAMM3kREREREGmDwJiIiIiLSAIM3EREREZEGGLyJiIiIiDTA4E1EREREpAEG73kqEAgku4Q5hf1QYz/U2A819kON/VBjP9TYD5pJDN7zlCzLyS5hTmE/1NgPNfZDjf1QYz/U2A819oNmEoM3EREREZEGGLyJiIiIiDTA4E1EREREpAEGbyIiIiIiDTB4ExERERFpgMGbiIiIiEgDDN5ERERERBpg8CYiIiIi0gCDNxERERGRBhi8iYiIiIg0wOBNRERERKQBBm8iIiIiIg0weBMRERERaYDBm4iIiIhIAwzeREREREQa0Ce7AKJkCQaDuHr1Ktra2qDX67Fq1SqsWrUKgiAkuzQiIiJagBi8aVEKh8N444034HQ6Y9u6urrQ29uLnTt3JrEyIiIiWqg41YQWpYaGBlXoHnHjxg243e4kVEREREQLHYM3LUrd3d0JtyuKMu4+IiIiovvB4E2LktVqndY+IiIiouli8KZFqby8HKIY//K32+0oLCxMQkVERES00DF406KUnp6Oxx57TDW6nZWVhf3793NVEyIiIpoVXNWEFq1ly5ahpKQE/f39MBgMSE9PT3ZJREREtIAxeNOiJooicnJykl0GERERLQKcakJEREREpAEGbyIiIiIiDTB4ExERERFpgMGbiIiIiEgDDN5ERERERBpg8CYiIiIi0gCDNxERERGRBgRFUZRkFzHXBQIByLKc7DJUJEmCTqdLdhlzBvuhxn6osR9q7Ica+6HGfqjNl36MvRIzzV0M3vOUz+fjL9kY7Ica+6HGfqixH2rshxr7ocZ+0EziVBMiIiIiIg0weBMRERERaYDBm4iIiIhIAwzeREREREQaYPAmIiIiItIAgzcRERERkQYYvImIiIiINMDgTURERESkAQZvIiIiIiINMHgTEREREWmAwZuIiIiISAMM3kREREREGmDwJiIiIiLSAIM3EREREZEGGLyJiIiIiDTA4E1EREREpAEGbyIiIiIiDTB4ExERERFpgMGbiIiIiEgDDN5ERERERBpg8CYiIiIi0gCDNxERERGRBhi8iYiIiIg0wOBNRERERKQBBm8iIiIiIg0weBMRERERaYDBm4iIiIhIAwzeREREREQa0Ce7AKLJUhQF3d3d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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "date_data = result_to_plot.loc[result_to_plot['variable']=='LC']\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y',color = 'value'), data = date_data)+geom_point(size =50, alpha = 0.8)+theme_bw()+scale_color_manual(values = ['grey','brown','orange','mediumaquamarine','royalblue','orchid'])+ggtitle('LC')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "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yZIlmmksRERDiaD2ZoIhERERERH1CEe0iYiIiIh0wKBNRERERKQDBm0iIiIiIh0waBMRERER6YBBm4iIiIhIBwzaREREREQ6YNAmIiIiItIBgzYRERERkQ4YtImIiIiIdMCgTURERESkAwZtIiIiIiIdMGgTEREREemAQZuIiIiISAcM2kREREREOmDQJiIiIiLSAYM2EREREZEOGLSJiIiIiHTAoE1EREREpAMGbSIiIiIiHTBoExERERHpgEGbiIiIiEgHDNpERERERDpg0CYiIiIi0gGDNhERERGRDhi0iYiIiIh0wKBNRERERKQDBm0iIiIiIh0waBMRERER6YBBm4iIiIhIBwzaREREREQ6YNAmIiIiItIBgzYRERERkQ4YtImIiIiIdMCgTURERESkAwZtIiIiIiIdMGgTEREREemAQZuIiIiISAcM2kREREREOmDQJiIiIiLSAYP2JSwQCCS6hAGF/dBiPzqxF1rshxb70Ym90GI/6EIxaF/CFEVJdAkDCvuhxX50Yi+02A8t9qMTe6HFftCFYtAmIiIiItIBgzYRERERkQ4YtImIiIiIdMCgTURERESkAwZtIiIiIiIdMGgTEREREemAQZuIiIiISAcM2kREREREOmDQJiIiIiLSAYM2EREREZEOGLSJiIiIiHTAoE1EREREpAMGbSIiIiIiHTBoExERERHpgEGbiIiIiEgHDNpERERERDpg0KYhzxMJ4qinCQ0BT6JLISIiokHEkOgCiBJFVVVsbDiC0tZKyFABAPnWFNwxfDJsBlOCqyMiIqJLHUe0acj6vK0an7SeioZsADjlb8P6uvIEVkVERESDBYM2DVm7XTVxtx/zNMEbCfVzNURERDTYMGjTkOWT44dpBYBfDvdvMURERDToMGjTkFVoS4u7PdlgQZrJ1s/VEBER0WDDoE1D1pz0Ijgk7ZceRQALssZAFITEFEVERESDBlcdoSErxWTF1wtn4bPWStQEXHAaLJiROgLDrMmJLo2IiIgGAQZtGtKSjGbMzxqd6DKIiIhoEOLUESIiIiIiHTBoExERERHpgEGbiIiIiEgHDNpERERERDpg0CYiIiIi0gGDNhERERGRDhi0iYiIiIh0wKBNRERERKQDQVVVNdFFDHSBQACKoiS6jBiyLEOSpESXMWCwH1rsRyf2Qov90GI/OrEXWpdSP2w2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8l8wGJzhUc8MQRAKPYQ5hfGwmsvx2OCvQYnizDq+pbgebtk+499vLseiEBgPK8Yjg7GwYjxouub9jHZ/fz9EUURpaWn6WEVFBa5evTrhY86dO4fvf//78Hg82Lx5M2677bb0uUOHDuHtt9+2XL99+3bs2LFj5gc/TQ4HuzOMxXhYzeV4qJINX224DR8OXMOlcD/sooz1/mo0eyvz8v3mciwKgfGwYjwyGAsrxoOma94n2olEAna7dQZMVVXE4/Gc169ZswZtbW1wu91ob2/Hz3/+c6iqirVr1wIA2tra0NTUZHmM2+3Oz+CnKRqN8kVgDMbDaq7HwyHZsL1sGbaXLcv795rrsZhtjIcV45HBWFgxHjRdcz7RfvHFFyecna6rq8OuXbuykup4PJ6VfI8aW7ddX1+PLVu24NSpU+lE2+v1wuv1ztDo84tt0KwYDyvGI4OxsGI8rBiPDMbCivGg6ZrzifbTTz896flEIgHDMNDf34+SkhIAQFdXF8rKyqb09QVB4C8SEREREc24eb8YUlEUrF69Gvv27UMikcC1a9dw9uxZtLa25rz+zJkziEajME0T7e3tOHDgAFatWjXLoyYiIiKihW7Oz2hPxUMPPYQ9e/bghz/8IRwOBx566KF0icjVq1fx8ssv4/nnnwcAnDx5Env27EEymYTX68XWrVuxfv36Qg6fiIiIiBYgwWTdxLwViUTgdGa3SFusGA8rxiODsbBiPKwYjwzGworxoOma96UjRERERERzERNtIiIiIqI8YKJNRERERJQHTLSJiIiIiPKAiTYRERERUR4w0SYiIiIiygMm2kREREREecBEm4iIiIgoD5hoExERERHlARNtIiIiIqI8YKJNRERERJQHTLSJiIiIiPKAiTYRERERUR4w0SYiIiIiygMm2kREREREecBEm4iIiIgoD5hoExERERHlARNtIiIiIqI8YKJNRERERJQHTLSJiIiIiPKAiTYRERERUR4w0SYiIiIiygMm2kREREREecBEm4iIiIgoD5hoExERERHlARNtIiIiIqI8YKJNRERERJQHTLSJiIiIiPKAiTYRERERUR4w0SYiIiIiygMm2kREREREeSCYpmkWehBzXSwWg2EYhR5GFl3XIUlSoYcxZzAeVoxHBmNhxXhYMR4ZjIXVfIqH0+ks9BAoByba81gkEuEv1hiMhxXjkcFYWDEeVoxHBmNhxXjQdLF0hIiIiIgoD5hoExERERHlARNtIiIiIqI8YKJNRERERJQHTLSJiIiIiPKAiTYRERERUR4w0SYiIiIiygMm2kREREREecBEm4iIiIgoD5hoExERERHlARNtIiIiIqI8YKJNRERERJQHTLSJiIiIiPKAiTYRERERUR4w0SYiIiIiygMm2kREREREecBEm4iIiIgoD5hoExERERHlARNtIiIiIqI8YKJNRERERJQHTLSJiIiIiPKAiTYRERERUR4w0SYiIiIiygMm2kREREREecBEm4iIiIgoD5hoExERERHlARNtIiIiIqI8YKJNRERERJQHTLSJiIiIiPKAiTYRERERUR4w0SYiIiIiygMm2kREREREecBEm4iIiIgoD+RCD2C6Dhw4gKNHj6KnpwctLS149NFHJ71+//79eO+996BpGpqbm/Hwww9Dlud9GIiIiIhojpn3M9oejwd33303NmzYcNNrL1y4gPfeew9f/epX8Zd/+ZcYHBzEvn37ZmGURERERLTYzPup3ObmZgBAZ2cnNE2b9NqjR49iw4YNKC8vBwBs374du3fvxv3335++JhgMIhQKWR7ndrvh9XpneOTTJwhCoYcwpzAeVoxHBmNhxXhYMR4ZjIUV40HTNe8T7VvR29uLVatWpf9eUVGBcDiMSCQCp9MJADh06BDefvtty+O2b9+OHTt2zOpYp8LhcBR6CHMK42HFeGQwFlaMhxXjkcFYWDEeNF2LKtFOJBKw2+3pv6uqCgCIx+PpRLutrQ1NTU2Wx7nd7tkb5C2IRqN8ERiD8bBiPDIYCyvGw4rxyGAsrBgPmq45nWi/+OKLuHr1as5zdXV1eOaZZ27p6ymKgng8nv776J/HJt9er3dOlonkYppmoYcwpzAeVoxHBmNhxXhYMR4ZjIUV40HTNacT7aeffnpGv15ZWRm6u7vR0tICAOjq6oLL5UrPZhMRERERzZR533VE13VomgbTNGGaJjRNg67rOa9tbW3F4cOH0dPTg2g0infeeQfr16+f5RETERER0WIwp2e0p+Kdd96xLF48fvx4evHi0NAQXnjhBTz33HPw+/1YsWIFtm7din/5l39J99Gei4sciYiIiGj+E0wWIM1bY7ulEOMxHuORwVhYMR5WjEcGY2HFeNB0zfvSESIiIiKiuYiJNhERERFRHjDRJiIiIiLKAybaRERERER5wESbiIiIiCgPmGgTEREREeUBE20iIiIiojxgok1ERERElAdMtImIiIiI8oCJNhERERFRHjDRJiIiIiLKAybaRERERER5wESbiIiIiCgP5EIPgIiIgORwEuFTIRgxA2q9CrXRAUEQCj0sIiKaBibaREQFFr0YQd9rPTCTJgBg+GAAjqUOlH62AoLEZJuIaL5i6QgRUQGZSRP9v+lNJ9mjopeiCJ8KFWhUREQ0E5hoExEVULwjBiNq5DwXOR+e5dEQEdFMYqJNRFRIk1SGsESbiGh+Y6JNRFRA9hoVklvKec7Z5J7l0RAR0Uxiok1EVECCJKDk02UQFOv0tWu1C85VrgKNioiIZgK7jhARFZha70D1H9chei4MPWpArXfAXmUv9LCIiGiamGgTEc0BkirBvc5b6GEQEdEMYukIEREREVEeMNEmIiIiIsoDJtpERERERHnARJuIiIiIKA+YaBMRERER5QETbSIiIiKiPGCiTURERESUB+yjTUQzovfIEVzeswehjg64a2qw5JFHULZhQ6GHRUREVDCCaZpmoQcx18ViMRiGUehhZNF1HZIkFXoYcwbjYTWb8eg9eBAf/+hHWcfX/Of/jLK2tlkZw2R4b1gxHlaMRwZjYTWf4uF0Ogs9BMqBM9pToKpqoYeQUyQS4S/WGIyH1WzGo33vXohidiVa+549aNi2bVbGMBneG1aMhxXjkcFYWDEeNF2s0SaiaTF0HcPXruU8N3ztGoxkcpZHRERENDcw0SaiaRElCfbi4pzn7MXFEGV+cEZERIsTE20imrbGXbtu6TgREdFiwKkmIpq2xs98Bno8jiu/+hWSkQhkpxONu3ah8TOfKfTQiIiICoaJNhFNmyAIWP6FL2DJI48gPjQEu98PSVEKPSwiIqKCYqJNRDNGUhQ4y8sLPQwiIqI5gTXaRERERER5wESbiIiIiCgPmGgTEREREeUBE20iIiIiojxgok1ERERElAdMtImIiIiI8oCJNhERERFRHjDRJiIiIiLKAybaRERERER5wESbiIiIiCgPmGgTEREREeUBE20iIiIiojxgok1ERERElAdMtImIiIiI8oCJNhERERFRHjDRJiIiIiLKAybatygYDGLfvn0IBoOFHgqcTmehh8B4jMN4ZDAWVoyHFeORwVhYMR5WcykedOuYaN+iUCiEt99+G6FQqNBDmRMYDyvGI4OxsGI8rBiPDMbCivGwYjzmNybaRERERER5wESbiIiIiCgPmGgTEREREeWB9J3vfOc7hR7EfGKaJhRFQWNjI+x2e6GHU3CMhxXjkcFYWDEeVoxHBmNhxXhYMR7zm2CaplnoQRARERERLTRyoQcwHxw4cABHjx5FT08PWlpa8Oijj056/f79+/Hee+9B0zQ0Nzfj4YcfhiwvnFBHIhHs3bsXFy9ehNPpxM6dO7Fu3bqc1+7btw/vvvsuJElKH3v22WdRXFw8W8OdcVN9/qZp4o033sDhw4cBABs3bsR9990HQRBme8h5NdV4LMR7Ybxbea1Y6K8TwNTjceTIEezdu9fy/L/0pS9hyZIlszXUvEsmk/jVr36FS5cuIRqNoqioCPfddx9WrFiR8/qFfn/cSjwWw/2xe/duXL58GYlEAm63G1u3bkVbW1vOaxf6vbHQ8CczBR6PB3fffTcuXrwITdMmvfbChQt477338NWvfhUejwc/+9nPsG/fPtx///2zNNr8e/311yFJEr75zW+iq6sLP/3pT1FZWYny8vKc169ZswaPPfbYLI8yf6b6/A8dOoQzZ87gT//0TyEIAl566SX4/X7cdtttBRp5ftzK/bDQ7oXxpvpasRheJ4Bbe+2sra3FM888M0sjm32GYcDr9eKP/uiP4PP5cP78efziF7/As88+i6KiIsu1i+H+uJV4AAv//ti2bRseeeQRyLKM3t5e/PM//zOqqqpQXV1tuW4x3BsLDRdDTkFzczNWr14Nh8Nx02uPHj2KDRs2oLy8HA6HA9u3b8fRo0dnYZSzI5FI4NSpU9ixYwfsdjsaGhrQ1NSEY8eOFXpos+JWnv/Ro0dxxx13wOfzwev14s4771xQ9wLA+2G8qb5WLPTXiVG38tq50CmKgh07dqCoqAiiKKKpqQl+vx83btzIunYx3B+3Eo/FoLy8PD0rLQgCBEHAwMBA1nWL4d5YaDijPcN6e3uxatWq9N8rKioQDocRiUTmxA5T09Xf3w9RFFFaWpo+VlFRgatXr074mHPnzuH73/8+PB4PNm/ePK9ndG/l+ff29qKystJyXW9v76yMc7bc6v2wkO6F6VjorxOfRFdXF37wgx/A4XCgtbUVd911l6XMaKEJhULo7+9HWVlZ1rnFeH9MFg9gcdwfr732Go4ePYpkMonKysqcZTSL8d6Y75hoz7BEImFZFayqKgAgHo8viF+C8c8PSD3HeDye8/o1a9agra0Nbrcb7e3t+PnPfw5VVbF27drZGO6Mu5Xnn+teSCQSME1zwdRp30o8Ftq9MB0L/XXiVjU0NODP/uzP4PP50Nvbi1/84hcQRRHbtm0r9NDyQtd17N69G+vXr8+ZWC62++Nm8Vgs98fDDz+MXbt24fr167hy5UrOuuvFdm8sBIs+0X7xxRcnnH2rq6u75ZowRVEsScbon+dLS56bxWPXrl1ZSVQ8Hp/w+Y2t062vr8eWLVtw6tSpeZtcjf/5AhM//1z3gqIoCybJBm4tHgvtXpiO+f46MdPGLoitqKjA9u3b8f777y+4RApI1Sa/8sorkCQJu3btynnNYro/phKPxXR/iKKIhoYGHD9+HB999BFuv/12y/nFdG8sFIs+0X766adn9OuVlZWhu7sbLS0tAFIfd7lcrnnzTvNm8UgkEjAMA/39/SgpKQGQeo4Tfdw3niAImM8dJUtKSqb8/Efvhdra2kmvm89uJR7jzfd7YTrm++tEvi3Ue8M0TezduxfhcBhf/vKXJyx9WCz3x1TjMd5CvT/GMgwDg4ODWccXy72xkHAx5BToug5N02CaJkzThKZp0HU957Wtra04fPgwenp6EI1G8c4772D9+vWzPOL8URQFq1evxr59+5BIJHDt2jWcPXsWra2tOa8/c+YMotEoTNNEe3s7Dhw4YL+HH/oAAAMVSURBVKkvm29u5fm3trZi//79CAaDCAaD2L9//4K6F4Bbi8dCuxdymeprxUJ/nRg11XicP38eoVAIQKoG9e23315w9waQqsHt7e3Fk08+CZvNNuF1i+X+mGo8Fvr9EQqFcOLECcTjcRiGgQsXLuDkyZM52xculntjIeGGNf9/O3esC9sWx3H85yhETiKTSbTeABERpUgoSTyD0Ign8AqCRhRaCqKZClGgoCEKtIhGlFOgEMmcxj0359ycxClW5g6fTznVf6/s7Hyz9pr9AYeHhzk+Pv7lt5GRkYyOjqZer2d1dTVzc3OpVCpJktPT05ycnHzab1y+vLykVqvl9vY2nZ2dGRsb+/nd5Pv7+2xsbGRhYSFJsrOzk5ubm7y9vaWrqytDQ0P/eRXWav50/b9fe6PRyMHBwS/f0R4fH/9UR0eSj6/HZ7wXfvenZ8XAwMCXe04kH1+P/f39XF5e5vX1Nd+/f09fX19GRkY+1Z/d6vV6VlZW0t7enm/f/t3jmpiYSE9Pz5e7P/5mPT77/fH8/Jzt7e08Pj6m0WikUqlkeHg4g4ODX7IxPhuhDQAABTg6AgAABQhtAAAoQGgDAEABQhsAAAoQ2gAAUIDQBgCAAoQ2AAAUILQBAKAAoQ0AAAUIbQAAKEBoAwBAAUIbAAAKENoAAFCA0AYAgAKENgAAFCC0AQCgAKENAAAFCG0AAChAaAMAQAFCGwAAChDaAC3o5uYm1Wo1FxcXSZKHh4d0d3fn6OiouYMB8FNbo9FoNHsIAP7e+vp6lpeXc35+nqmpqfT29mZxcbHZYwHwTmgDtLDJycnc3d2lra0tZ2dn6ejoaPZIALxzdASghc3MzOT6+jrz8/MiG+B/xo42QIt6enpKf39/RkdHs7u7m6urq1Sr1WaPBcA7oQ3Qoqanp/P09JStra3Mzs6mXq9ne3u72WMB8M7REYAWVKvVsre3l7W1tSTJ0tJSLi4usrm52eTJAPiHHW0AACjAjjYAABQgtAEAoAChDQAABQhtAAAoQGgDAEABQhsAAAoQ2gAAUIDQBgCAAn4A49qBrANCHboAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "date_data = result_to_plot.loc[result_to_plot['variable']=='MS_instrument']\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y',color = 'value'), data = date_data)+geom_point(size =50, alpha = 0.8)+theme_bw()+scale_color_manual(values = ['brown','mediumaquamarine','orchid'])+ggtitle('MS INSTRUMENT')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAuUAAAIhCAYAAADpQ8RcAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdeXxU9b3/8deZJZnsC2RjX2QJi2xiUFBARa0LtqCI2mpbbH+tt7Zqveq97e9Ke6uVrmqvrb9bW6UqWrQq7jsguKDsAoLsgex7Mplk1vP7YyBhyASSSHIS8n4+Hj4ezvfMOfPNh8nkPd/zPd9jmKZpIiIiIiIilrFZ3QERERERkd5OoVxERERExGIK5SIiIiIiFlMoFxERERGxmEK5iIiIiIjFFMpFRERERCymUC4iIiIiYjGFchGRbmDIkCHExcWRlJREamoq5557Lo8++iihUCjieYsXL8YwDNatW9fUdv/995OYmEhiYiIulwu73d70eOzYsQAYhkFCQkJTe2JiIr/5zW+69GcUEZHWGbp5kIiI9YYMGcJjjz3GRRddRE1NDatXr+YnP/kJs2bN4vHHHwfANE2GDx9OTU0NCxcu5JFHHmlxnCeeeILHHnuMtWvXRrQbhsHu3bs544wzuuTnERGR9tFIuYhIN5OSksLcuXP55z//ydKlS9m2bRsAa9asoaioiIcffphnn30Wn89ncU9FRORUUSgXEemmzj77bAYMGMCaNWsAWLp0KVdeeSULFiwA4JVXXrGyeyIicgoplIuIdGP9+vWjsrISj8fDc889x/XXX4/T6eTqq6/mH//4R7uONXnyZFJTU5v+e+uttzqp1yIi0l4OqzsgIiKtKygoID09nRdffBGHw8Fll10GwA033MBFF11EWVkZGRkZbTrWxo0bNadcRKSb0ki5iEg39dlnn1FQUMCMGTNYunQpbrebQYMGkZ2dzTXXXIPf72fZsmVWd1NERE4BhXIRkW6mtraWV199lYULF/LNb36T9PR03nvvPV599VU2b97M5s2b2bJlC3fffXe7p7CIiEj3pFAuItJNXHnllSQlJTFw4EDuu+8+7rjjDh5//HGefPJJJk6cyMUXX0x2dnbTfz/+8Y/ZunVr0+osJzNhwoSIdcpvu+22Tv6JRESkrbROuYiIiIiIxTRSLiIiIiJiMYVyERERERGLKZSLiIiIiFhMoVxERERExGIK5SIiIiIiFlMoFxERERGxmEK5iIiIiIjFFMpFRERERCymUC4iIiIiYjGFchERERERiymUi4iIiIhYTKFcRERERMRiCuUiIiIiIhZTKBcRERERsZhCuYiIiIiIxRTKRUREREQsplAuIiIiImIxhXIREREREYsplIuIiIiIWEyhXERERETEYgrlIiIiIiIWUygXEREREbGYQrmIiIiIiMUUykVERERELKZQLiIiIiJiMYVyERERERGLKZSLiIiIiFhMoVxERERExGIK5SIiIiIiFlMoFxERERGxmEK5iIiIiIjFFMpFRERERCymUC4iIiIiYjGFchERERERiymUi4iIiIhYTKFcRERERMRiCuUiIiIiIhZTKBcRERERsZhCuYiIiIiIxRTKe7DGxkaru9CtqB6RVI9mqkUk1SOS6tFMtYikekhXUijvwUKhkNVd6FZUj0iqRzPVIpLqEUn1aKZaRFI9pCsplIuIiIiIWEyhXERERETEYgrlIiIiIiIWUygXEREREbGYQrmIiIiIiMUUykVERERELKZQLiIiIiJiMYVyERERERGLKZSLiIiIiFhMoVxERERExGIK5SIiIiIiFlMoFxERERGxmEK5iIiIiIjFFMpFRERERCzmsLoDIlYqXb+evf/6F3X5+cRnZTHkiisYcMEFVndLREREehmFcum1SjdsYONvftP02H34MNsefZSgz8fgSy+1sGciIiLS22j6ivRa+158MXr7Sy9hhkJd3BsRERHpzRTKpdeqy8+P2u6trMRfV9fFvREREZHeTKFceq347Oyo7c6kJByJiV3cGxEREenNFMql1xo6d27U9iGXX47Nbu/i3oiIiEhvpgs9pdfqN2MGIZ+Pvf/6Fw1lZcSkpDD4sssY9vWvW901ERER6WUUyqVXG3DBBfSfPZuAx4MjLg7DppNHIiIi0vUUyqXXMwwDZ0KC1d0QERGRXkzDgiIiIiIiFlMoFxERERGxmEK5iIiIiIjFFMpFRERERCymUC4iIiIiYjGFchERERERiymUi4iIiIhYzDBN07S6E91dY2MjoVDI6m60EAwGset28E1Uj0iqRzPVIpLqEUn1aKZaROpJ9YiPj7e6C/IVKZT3YB6PR7+Ex1A9IqkezVSLSKpHJNWjmWoRSfWQrqTpKyIiIiIi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ungxJevWYYZCmIEARR9+yGe//CWhQNecGo932bj12jSy+zSvcpHdx86tC9JO60Au0hauGBu3XZdO7pAYDMAwYNywGG6/Lq3XBHIRke5CI+XSaYo+/JCGsrIW7fUFBZSuX0/2tGld0o+h/WJY/L0MCsvDXwT69dXbXuSo7D4OfrIwnQZvCMMIB3UREel6SifSadyHD3doW2dRGBdpXVyswriIiJX0KSydJnHAgA5tExEREeltFMql0+RMn05cRkaL9oT+/cmcOtWCHomIiIh0Twrl0mnssbGcvXgxWXl5GHY7hsNBzowZnH3vvd3i9uIiIiIi3YUm2UqnisvIYNJPfxpep9wwdFt7ERERkSgUyqVLdOZNg0RERER6OiUlERERERGLKZSLiIiIiFhMoVxERERExGIK5SIiIiIiFlMoFxERERGxmEK5iIiIiIjFFMpFRERERCymUC4iIiIiYjGFchERERERiymUi4iIiIhYTKFcRERERMRiCuUiIiIiIhZTKBcRERERsZhCuYiIiIiIxRTKRUREREQsplAuIiIiImIxhXIREREREYsplIuIiIiIWEyhXERERETEYgrlIiIiIiIWUygXEREREbGYQrmIiIiIiMUcVndApCuYoRD5b79NwerVBBsbyZg0iWFXXUVMSorVXRMRERFRKJfeYdujj1KwalXT4/qCAko3bODcX/8aR3y8dR0TERERQdNXpBeoLyyMCORHeYqKOPz++13fIREREZHjnDYj5R6Ph5dffpm9e/cSHx/PhRdeyJlnntnieStXrmTNmjXY7famth/+8Iekp6d3ZXelC1V/+WXr23bv7sKeiIiIiER32oTy119/Hbvdzp133klxcTHLli0jOzubzMzMFs8dO3Ys8+fPt6CXYoXYE3zhik1L68KeiIiIiER3Wkxf8fl87Nixg9mzZxMbG8vgwYMZNWoUW7ZsafexamtrKSwsjPivtra2E3r91RmGYXUXupXW6tFn3DgS+vdv+XyHg4Fz5nR2tyyj90cz1SKS6hFJ9WimWkRSPaQrnRYj5RUVFdhsNvr27dvUlpWVxcGDB6M+/8svv+SBBx4gKSmJs88+m6lTpzZt27BhA6tXr454/syZM5k9e3bndP4riIuLs7oL3Upr9TBsNqb8x3/w+f/8D1U7dwLg6tuXMd/9LolRwvrpQu+PZqpFJNUjkurR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63nqqafa9NrPPvssV199dYemPSmUi/QSVTt3UrF1a4t2T1ERRWvWWNAjERGRU8vv9zN//nxuuOEG5s2bB0BWVhZFRUVAeN55ZmbmCY/x7rvvMnToUDIyMnA6ncybN4+PPvqIPn36UF1dTSAQAODw4cP0798/Yt9nn32W6667rkN9VyiXbsFfX8/hlSs5+OabeIqLre5Ol2msqsJXW9slr1Wzb1+HtomIiPQEpmmyaNEicnNzueOOO5ra586dy9KlSwFYunQpV1111QmPM2jQID755BM8Hg+mafLee++Rm5uLYRjMnj2b559/Puqxdu7cSVVVFeecc06H+q/VV3qw0+UClLKNG9n84IMEj5lCMXzePEYsXNiu4/SketTs2cP2v/2N2r17Aegzfjxj/8//If4k397b4/h6lK5fz8bf/Cbqc0csXMjwIyMK3UUoGMR2ilY96Envja6gekRSPZqpFpFUj55l7dq1nHfeeYwfPx6bLTzufP/995OXl8eCBQvIz89n8ODBLF++nPT0dIqLiznrrLOora3FZrORmJjIjh07SE5O5t577+Wf//wnDoeDSZMm8dhjjxEbG8u+fftYuHAhlZWVTJo0iaeeeorY2FgAFi9eTGNjIw888ECH+q9Q3oOdDh8WgYYGVv3whwQ8nhbbzr73XtLHjm3zsXpKPbzV1ay57bYWP3N8djYz/vjHTguioWCQtXfcgefIKbyjHPHxnPfgg93iYs+aPXv44oknKPn0U4JeLwk5OQy58kpGLFiAzens8HF7ynujq6gekVSPZqpFJNVDupKmr4ilyjZtihrIAQrXru3i3rRfoKGBg2++yfb//V/2v/IKvrq6k+5TsGpV1J/ZU1xM2fr1ndFNAGx2O1N//nP6nHlmU1vy8OGc9bOfdYtAXrFtGx/efTf5b75JY0UFfreb6j172P3MM2z/61+t7p6IiEin0pKIYqnQkYslom47cpes7qqhrIx1995LY3l5U9v+FSs4+957SRw48IT7tcZzgm2nQlxGBlN//nN8tbWEAgFc6emd+nrtsfvZZ/FWVBBx8s40aayspGD1akZcey2uPn2s66CIiEgn0ki5WCpjwgQMR/TvhplTp3Zxb9rny2XLIgI5gK+2li8ef/yE+yUPHdrqtpRhw05J36LxlJZStWsXgYYGYpKTu1UgN0Mhqr/8kmCUL2JBrxcz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OaakXEREREQkx5SUi4iIiIjkmJJyEREREZEcU1IuIiIiIpJjSspFRERERHJMSbmIiIiISI4pKRcRERERyTEl5SIiIiIiOaakXEREREQkx5SUi4iIiIjkmJJyEREREZEcU1IuIiIiIpJjSspFRERERHJMSbmIiIiISI4pKRcRERERyTEl5SIiIiIiOaakXEREREQkx5SUi4iIiIjkmJJyEREREZEcU1IuIiIiIpJjSspFRERERHJMSbmIiIiISI4pKRcRERERyTHDtm0714MY66LRKJZl5XoYg6RSKRwOR66HMWYoHtkUj36KRTbFI5vi0U+xyDae4uH3+3M9BHmXlJSPY+FwWG/CARSPbIpHP8Uim+KRTfHop1hkUzxkNKl8RUREREQkx5SUi4iIiIjkmJJyEREREZEcU1IuIiIiIpJjSspFRERERHJMSbmIiIiISI4pKRcRERERyTEl5SIiIiIiOaakXEREREQkx5SUi4iIiIjkmJJyEREREZEcU1IuIiIiIpJjSspFRERERHJMSbmIiIiISI4pKRcRERERyTEl5SIiIiIiOaakXEREREQkx5SUi4iIiIjkmJJyEREREZEcU1IuIiIiIpJjSspFRERERHJMSbmIiIiISI4pKRcRERERyTEl5SIiIiIiOaakXEREREQkx5SUi4iIiIjkmJJyEREREZEcU1IuIiIiIpJjSspFRERERHJMSbmIiIiISI4pKRcRERERyTEl5SIiIiIiOaakXEREREQkx5y5HsC79dprr7Fjxw5aWlpYsGABt9122xnvv3nzZjZt2kQikWDevHncdNNNOJ3jPgwiIiIiMo6N+5nyvLw8Vq1axaWXXnrW+x48eJBNmzZxzz338LnPfY7Ozk6ef/75URiliIiIiMjwxv0U8bx58wA4ceIEiUTijPfdsWMHl156KeXl5QCsXr2axx9/nLVr12bu09PTQygUynpcMBgkPz//Ao/83TMMI9dDGFMUj2yKRz/FIpvikU3x6KdYZFM8ZDSN+6T8fLS2tjJ37tzMzxUVFfT19REOh/H7/QBs27aNF198Metxq1evZs2aNaM61nPh8/lyPYQxRfHIpnj0UyyyKR7ZFI9+ikU2xUNG03sqKY/H43g8nszPXq8XgFgslknKlyxZwpw5c7IeFwwGR2+Q5yESiegPxgCKRzbFo59ikU3xyKZ49FMs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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "date_data = result_to_plot.loc[result_to_plot['variable']=='shortdate']\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y',color = 'value'), data = date_data)+geom_point(size =50, alpha = 0.8)+theme_bw()+scale_color_manual(values = ['grey','brown','orange','mediumaquamarine','royalblue','orchid'])+ggtitle('DATE')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n" - ] - }, - { - "data": { - "image/png": "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jjuoq6ujtraW+vp6ysvLee2112hoaADAtm22b9/OlClT+u3f1dXFXXfdxU033UReXt6Qtk092yIiIiIyJAa6eTHZKioquO++++KWrV27lk984hPk5+cTDocBWL58OV/84hd7t1m1ahWO42DbNjfffDP/8A//MORt0zzbo5jm/4ynevRRLeKpHvFUj3iqRx/VIp7qIUNBw0hERERERJJEYVtEREREJEkUtkVEREREkkRhW0REREQkSRS2RURERESSRGFbRERERCRJFLZlzLFtzWYpIiJyPlq/fj2GYVBdXf2+21555ZVMnjw57hHtN910E5mZmUPaJoVtGXKO4xCKxbCHeQr3o4ccXv5tiGcqQry4PkTtntiwHl9ERERSq6KighUrVlBRUXFW2+fm5vL6668D0N7eztGjR4e8TXqCpAypTUePseFgLU3BINlpaVw3aSJrpkzGMIy47aIRh/r9Fu0tNul+g8kzXGRkDf7c70htjHf/CKbZE/CD3Q47t0SxbZg6Rx9zkZEm0mTTtT2G1e3gnWCSOd+N6TPef0cRGdF+9IulST/GZ/78nYTLu7q62LRpExs3buTGG2/kgQce4OWXX+brX/86hYWF7Ny5k2XLlvGLX/yiN5esW7eORx99lBUrVvDEE09wyy238O677wLw8ssv861vfYunn34agC9+8YtccMEF3HnnnefUXqUQGVBbOMxvDhykqvk4btPk4pJibiovw+dO/LF5u7GJH+/a3fu6IxLh1/sPYDsOHykv610eCjq88fswga6+nu+De2JceGUaReNcg2rr/ncT92If2B2jfLarX9gXkdTp3hOj5ZkonPwTENxv07XDouSjXlx+/a6KyOBs2LCB1atXM3PmTAoKCqis7Hl0/NatW3n33XcZP348l112Ga+//jorVqwA4Oqrr+bTn/40lmXx6KOP8qMf/YhvfOMbQ9ouDSORhEKxGP+3ciuvNRylMxqlLRzm2UP1PLRtx4D7PHPoUMLlz9cfJmbbva/37YzGBW0A24adf4wOur1dHYmHrISCDtHIoN9WRIaYYzm0vxzrDdqnxNocOis19EtEBq+iooJ169YBPT3Wp4aSLF++nIkTJ2KaJosXL6a2trZ3H5fLxYoVK3j00UcJBoOUlZUNebvUsy0JvdHYSFMw2G/5nvZ2qtvamZ2X229dY6D/9gBd0Sjd0Sg5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IiIiOaJiW0REREQkR1Rsi4iIiIjkiIptEREREZEcUbEtIiIiIpIjKrZFRERERHJExbaIiIiISI6o2BYRERERyREV2yIiIiIiOaJiW0REREQkR1Rsi4iIiIjkiIptEREREZEcUbEtIiIiIpIjKrZFRERERHJExbaIiIiISI6o2BYRERERyREV2yIiIiIiOaJiW0REREQkR1Rsi4iIiIjkiIptEREREZEcUbEtIiIiIpIjKrZFRERERHJExbaIiIiISI644x3An+qFF15gy5YttLa2smjRIt72tred8/oNGzbw7LPPkkwmWbBgAbfccguuO+nTICIiIiIT0KQf2S4oKGDdunUsW7bsvNfu37+fZ599ljvvvJP77ruPzs5OnnjiiTGIUkREREQuRZO+2F6wYAHz588nLy/vvNdu2bKFZcuWUVlZSV5eHldffTVbtmwZgyhFRERE5FJ0SfVPtLW1MW/evIHHVVVV9Pf3E4lECIVCAPT09NDX15f1vHA4TGFh4ZjGeiEsyxrvECYU5WOQcpFN+cimfGRTPgYpF9mUDxkNl1SxnUgkCAQCA4+DwSAA8Xh8oNh+6aWXeOqpp7Ked/XVV3PttdeOXaAX6EJG8y8lyscg5SKb8pFN+cimfAxSLrIpHzIaJnSx/a1vfYvDhw+PeG7atGm8//3vf02v5/f7icfjA49P/31oAb5ixQrmzp2b9bxwOPya7jNWotGofhEMoXwMUi6yKR/ZlI9syscg5SKb8iGjYUIX23ffffeovl5FRQUtLS0sWrQIgObmZvLz8wdGtQEKCwsnZMvISIwx4x3ChKJ8DFIusikf2ZSPbMrHIOUim/Iho2HST5BMp9Mkk0mMMRhjSCaTpNPpEa9dunQpmzdvprW1lWg0ytNPP01jY+MYRywiIiIil4oJPbJ9IZ5++umsHutt27YN9Fh3dXXxla98hXvuuYfi4mJmz57NlVdeyXe+852BdbYnYi+2iIiIiFwcLKPPSCatoauoiPIxlHKRTfnIpnxkUz4GKRfZlA8ZDZO+jUREREREZKJSsS0iIiIikiMqtkVEREREckTFtoiIiIhIjqjYFhERERHJERXbIiIiIiI5omJbRERERCRHVGyLiIiIiOSIim0RERERkRxRsS0iIiIikiMqtkVEREREckTFtoiIiIhIjqjYFhERERHJERXbIiIiIiI54o53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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "info = labels[['PID']]\n", - "info = info.loc[x_90_before.index,:]\n", - "result_to_plot = pd.merge(result,info, left_index = True, right_index = True)\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y',color = 'PID'), data = result_to_plot)+geom_point(size =50, alpha = 0.8)+theme_bw() #+scale_color_manual(values = ['brown','mediumaquamarine','orchid'])+ggtitle('MS INSTRUMENT')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(272, 25427)\n", - "(236, 157)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/tzx804/env/fixjupyter/lib/python3.7/site-packages/ipykernel_launcher.py:11: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", - " # This is added back by InteractiveShellApp.init_path()\n" - ] - } - ], - "source": [ - "## PCA\n", - "x_90_after = coverage(x.loc[labels['datetime']>='2019-06-01',:], 0.9,0.9)\n", - "print(x.loc[labels['datetime']>='2019-06-01',:].shape)\n", - "print(x_90_after.shape)\n", - "data_after_pca = log_z_zeroone_na(x_90_after)\n", - "\n", - "result, args = runPCA(data_after_pca)\n", - "result.set_index(x_90_after.index, inplace = True)\n", - "\n", - "info = labels[['index','MS_instrument', 'LC','ColumnLength','shortdate','PID']] \n", - "info['ColumnLength'] = labels.ColumnLength.astype(int).astype(str)\n", - "info = info.loc[x_90_after.index,:]\n", - "result_to_plot = pd.merge(result,info, left_index = True, right_index = True)\n", - "result_to_plot = pd.melt(result_to_plot, id_vars =['index','x','y'], value_vars =['MS_instrument','LC','ColumnLength','shortdate','PID']) " - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/tzx804/env/fixjupyter/lib/python3.7/site-packages/ipykernel_launcher.py:4: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", - " after removing the cwd from sys.path.\n" - ] - }, - { - "data": { - "image/png": "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fvihXn755W9Vp/QtHlCwYMECFRQUfOsdAAAAAF3t0KFD6t+/v+dzUlKSDh061O4cf39/9erVS5WVle2uW1RUpLi4ON1+++0aPny47rzzTtXV1XnmPfzww+rfv7/++te/6rHHHpN06sX2VVVVuuSSSzRy5Ej95S9/kSQNGzZM69evV2VlpRwOh1atWqWDBw9KOhXCEhMT23zw1mkvvfSSrrrqKkk6Y12StH79esXHx2vw4MGesaKiIg0fPlyTJk3S+vXrO9XXt956Szk5OZo1a5an3tzcXL333ntyOBw6duyY1qxZ41l2mtPp1GuvvaapU6d6xv7nf/5HQ4cO1fTp0/XnP//ZM97Q0KBRo0Zp3LhxWr68dWBevny5pkyZclZPTO502HG5XLryyis1bNgwLVq0yJPSAAAAAF/U3NysrVu36sc//rE+//xzhYWF6YknnvAs/81vfqODBw9q7ty5euaZZzzrbNmyRe+8847ef/99/epXv9JXX32ljIwMPfjgg7riiis0depU5eXlyc/PTw6HQ48//rgnLLVlzZo1eumll7Ro0aJO1SVJS5cu1Y033uj53LdvXx04cECff/65/vM//1M33XSTampqOjz+7373uyouLtb27dt1+eWX67bbbpMkXXHFFZo2bZq+853v6MYbb9T48ePl5+fXYt27775bEydO1IQJEzxj1113nXbv3q3ly5frF7/4hWe8pKREn332mZYsWaJ///d/1759+zo8lm+j02Hn6aef1uHDh/XEE0+ooKBAGRkZuuyyy/SXv/xFtbW1Z7VzAAAA4HxITExscXahtLRUiYmJ7c5pbm5WdXW1YmJi2l03KSlJSUlJGjt2rKRTl75t3bq11b7nzp2rt956S9Kps0JXXnmlwsLCFBsbq4kTJ2rbtm2SpDvuuENbtmzRunXr1Lt3bw0ZMkT79u1TUVGRcnNzNXDgQJWWlmrEiBEqKyuTJG3fvl133nmnVqxY4XnX5Jnqam5u1ttvv60bbrjBMxYUFORZf+TIkRo0aJC++uqrDnsaExOjoKAgSdKdd96pLVu2eJY9/PDDKigo0AcffCBjjIYMGeJZ9uijj6qiokL/+Z//2eZ2J06cqP379+vYsWOe/y6SlJqaqksuuUSff/65Z+6xY8e0efNmTZ8+vcNa2/Ot3rPj5+enq6++WkuXLtU///lPVVRUaN68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K6+8knrNySefTF1dHXPnzmXu3Lm0t7cDcP/991NUVJRq333T0UAgQGVlZdpGmDfffDNVVVVkZmaO2P8nn3wSTdNYtmxZqu22226jtraWurq6tP1nLr/8coqLi1Obhg76/ve/z7Rp05g9ezZf+MIX6O3tBeDhhx9O9XXu3Lnous6KFSsAOPvss5kzZw4zZ87k6quvxrZtAFasWMGCBQuYO3cu8+bN47333gOgr6+P8847L/WawT17AAzDSL3HwoULU+2LFy9mzpw5zJ49mwsuuIBgMJg69vjjjzNjxgxmzpzJRRddNGJsPjIlxp1QKHSgu/CpMl7j3RzqVVe+cv+If1d0Nh6wfo3XeB+sJN5jS+I9tiTe44tlWaqmpkbV19erWCymZs+erdauXZt2zt13362uuuoqpZRSjz76qPryl7+slFLqrrvuUpdeeqlSSqm2tjZ1xBFHKNu2lVJKnXTSSepf//rXsPe777771Le+9a1R+/Ptb39bXXjhhWnnvP3226q5uVllZGQMOz8QCKgTTjhBHX300an3W7t2rZo9e7aKRqNq69atqqamRlmWpZRS6tVXX1XLly9XM2fOTLvO888/rxKJhFJKqRtvvFHdeOONw95r1apVqqamJvV1X1+fUkopx3HU+eefrx599FGllFJnnHGGevbZZ5VSSj3zzDPqpJNOUkopdeutt6au297ervLy8lQsFlNKqRHvbeh7KKXUd7/7XXXbbbcppZTatGmTmjt3ruru7lZKJeO/P8k0NiHEiNZ279zDsWbmFFSNYW+EEEIcClqf/+SnOZeeNfLsgvfee4/a2lpqamoAWLRoEU899RQzZsxInfPUU09xyy23AHDBBRdwzTXXoJRi3bp1nHrqqQAUFxeTm5vLsmXLOOqooz5SH5cvX05bWxtnn3122ijNggULRn3Nj370I37wgx9w++23p/V30aJFeDweqqurqa2t5b333uOYY47hxBNPTI1MDXXmmWemvd8TTzwx7JxHH32URYsWpb7Ozs4GwLIs4vE42sB0dU3TCAQCQHI0p7y8PNXe39+PUopgMEh+fj6muee0YvA9lFJEIpHUe/zhD3/gW9/6Fnl5eUAy/vuTTGMTQozIZ7o+0jEhhBDiQNi5cydVVbt+EVdZWcnOnTtHPcc0TXJycujq6mLOnDksXboUy7LYtm0by5cvZ8eOHanXXXbZZcydO5f/+q//Qg2Zyv3kk0+mpmUNnu84Dtdffz2//OUv97nv77//Pjt27ODcc8/90Pe0J3/605/4zGc+M6z9scce48ILL0xrO+ussyguLiYrK4sLLrgAgDvvvJPvf//7VFVVccMNN3DbbbcBcM0117B+/XrKy8uZNWsWv/nNb9D1ZFoRjUaZN28eCxYs4O9//3vae1x22WWUlpayYcMGrr32WgA2bdrEpk2bOO6441iwYAHPPffcPt/fvpBkRwgxosMLJ+Ixhic1mqaxoLjmAPRICCGE+GRcfvnlVFZWMm/ePK677jqOPfZYDMMAkmtdVq9ezeuvv87rr7/Ogw8+CMB5553H9u3bWbVqFWeccQaXXHIJAPfccw/nnHMOlZWV+/TejuPwve99j1/96lf79Z5uvfVWTNPkq1/9alr7u+++i9/vH7bW5/nnn6elpYVYLMZLL70EwL333ssdd9zBjh07uOOOO1i8eHHq3Llz59Lc3MyKFSu45pprUiNADQ0NLFu2jEceeYTrrruO+vr61Hvcd999NDc3M336dB577DEgOZq0efNmXnnlFR599FGuvPLK1Dqj/UGSHSHEiPymm2/MPJkMlyfV5jZMLp56DGUZuQewZ0IIIcRwFRUVaaMxTU1NVFRUjHqOZVn09fVRUFCAaZrccccdrFixgqeeeore3l6mTp2aeg1AVlYWF110UWqRfkFBAR5P8v/IK664guXLlwPw9ttvc9dddzFp0iRuuOEGHnjgAW666aZR+93f38+aNWs4+eSTmTRpEu+88w4LFy5k2bJl+3RPI7n//vt5+umnefjhh1PTxQYtWbJk2KjOIK/Xy+c+9zmeeuopAP785z9z/vnnA/ClL30pde/33Xcf559/PpqmUVtbS3V1NRs2bEiLV01NDSeffDIffPBB2nsYhsGiRYt48skngeRo1cKFC3G5XFRXVzN16lQ2b96813vcV5LsCCFGNSOvnF8s+BLfOuxUvj7jJH6x4AKOK51yoLslhBBCDDN//nw2b97Mtm3biMfjLFmyJK0aGMDChQv585//DMATTzzBqaeeiqZphMNhQqEQAC+88AKmaTJjxgwsy6KzsxOARCLB008/nRoRaWlpSV136dKlTJ8+HUiOBDU2NrJ9+3Z++ctfcvHFF49YGW5QTk4OnZ2dbN++ne3bt7NgwQKWLl3KvHnzWLhwIUuWLCEWi7Ft2zY2b96813VEzz33HL/4xS9YunQpfr8/7ZjjODz++ONp63WCwWDqXizL4plnnmHatGkAlJeX8+qrrwLw0ksvMWVK8hlgwoQJvPjiiwC0tbWxceNGampq6OnpIRaLAdDZ2cmbb77JjBkzUEqxZcsWILlmZ+nSpan3+PznP5+qftfZ2cmmTZtS6672BylQIITYI5duSDECIYQQ+2S04gFjwTRN7rrrLs466yxs2+byyy9n5syZ/PjHP04lDosXL+ZrX/satbW15Ofns2TJEgDa29s566yz0HWdioqK1FS1WCzGWWedRSKRwLZtTj/9dK688koAfvvb37J06VJM0yQ/P5/7779/r3288cYbeeSRRwiHw1RWVnLFFVekCiaMZObMmXz5y19mxowZmKbJ3XffnZped+GFF/LKK6/Q2dlJZWUl//mf/8nixYu55ppriMVinHHGGUCySMH//M//APDaa69RVVWVlkyEQiEWLlxILBbDcRxOOeUUrr76aiBZPOA73/kOlmXh9Xr5/e9/DySLKVx66aXMmjULpRQ///nPKSws5K233uKqq65C13Ucx+Gmm25ixowZOI7DJZdcQiAQQCnFnDlzuPfee4HkWqF//OMfzJgxA8MwuP322ykoKNjXb/teaUrJhhnjTTgcHpbJi0+OxHtsSbzHlsR7bEm8x5bEW4jxT6axCSGEEEIIIcYlSXaEEEIIIYQQ45IkO0IIIYQQQohxSZIdIYQQQgghxLh0yFRjC4fDLF26lPr6evx+P6eddhqzZ88edt6bb77JihUr6Ovrw+/3M3/+fI477rjU8TvuuINQKJSqOV5VVcXFF188ZvchxMEm4Vis6dxOXzxEdXYpE7NLDnSXhBBCCCH2i0Mm2Xn22WcxDIMbbriB1tZWHnnkEUpLSykuLk47TynFF77wBUpKSujp6eHBBx8kOzubWbNmpc658MILmTx58ljfghAHnZZQN79b/TSBeDjVNquwmounnY6hGwewZ0IIIYQQH98hMY0tHo+zbt06TjnlFDweDxMnTqSuro6VK1cOO/f444+nvLwcwzAoLCykrq4ubefZvQkEAjQ3N6f9DQQC+/N2PnG775QrPlmHcrwf3vhiWqIDsLpzG280rz1APdq7QznehyKJ99iSeI8tibcQ498hMbLT1dWFrusUFham2kpKSmho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vLxxj29BQQG6u7tRXl4+5nk0uomM99l4Lc+s09f30qVLAcR/L2azmd96Zwiv78lRVRVbt26F3+/HrbfeOuoyQF7fROfGBAWUFTqdDnV1ddi2bRsikQhaWlpw9OhRrFixIu35R44cQTAYhKqqaGtrw86dO5PWKVOyiYzvihUr8M4778Dj8cDj8eCdd97BypUrs9DruWsi481reXrIsoxoNApVVaGqKqLRKGRZTjlvxYoV2L17N3p6ehAMBvHGG2/w+p6E8Y738ePH4fP5AMT3k2zfvp3X9yS89NJL6O3txS233AKtVjvqeby+ic6NRUUpawKBAF588UU0NTXBaDRi06ZNibokzc3NeOyxx3D33XcDAJ599lk0NjYiFovBZrNhzZo1WLduXTa7P+uNNr5nj62qqvjzn/+cVGfnyiuv5DK2CRrvePNanh7btm3D9u3bk9rWr1+PVatW4Wc/+xnuuOMOOBwOAMDbb7+Nt956i3VIpmC84/3HP/4R+/fvRyQSgdlsxvLly7F+/XomKJiAoaEh/PjHP4YkSRDFM99JX3/99aisrOT1TTRBDHaIiIiIiCgncRkbERERERHlJAY7RERERESUkxjsEBERERFRTmKwQ0REREREOYnBDhERERER5SQGO0RERERElJMY7BARERERUU5isENERERERDmJwQ4REREREeUkBjtERERERJSTGOwQEREREVFOYrBDREREREQ5icEOERERERHlJAY7RERERESUkxjsEBERERFRTmKwQ0REREREOYnBDhERERER5SQGO0RERERElJMY7BARERERUU5isENERERERDmJwQ4R0RzU2NgIl8uF3bt3AwA6OjpQUFCA119/PbsdIyIimkUEVVXVbHeCiIgm7le/+hXuv/9+vPfee7jpppuwbNky/OhHP8p2t4iIiGYNBjtERHPY5s2bcfLkSQiCgL/+9a/Q6/XZ7hIREdGswWVsRERz2Gc/+1kcPHgQX/rSlxjoEBERnYUzO0REc5TP58OKFSuwYcMGvPLKKzhw4ABcLle2u0VERDRrMNghIpqjbrvtNvh8Pjz11FP43Oc+h6GhITz99NPZ7hYREdGswWVsRERz0Isvvog//OEP+PnPfw4AuO+++7B79248/vjjWe4ZERHR7MGZHSIiIiIiykmc2SEiIiIiopzEYIeIiIiIiHISgx0iIiIiIspJDHaIiIiIiCgnMdghIiIiIqKcxGCHiIiIiIhyEoMdIiIiIiLKSQx2iIiIiIgoJ/1/uO2hIuPkRN0AAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# look at missing values\n", - "miss = x_90_after.T.isnull().sum().astype(float).tolist()\n", - "date_data = result_to_plot.loc[result_to_plot['variable']=='shortdate']\n", - "date_data['missingness']=[(mis/x_90_after.shape[1]) for mis in miss]\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y', color='missingness'),data = date_data)+geom_point(size =50, alpha = 0.8) + scale_color_gradient(low = \"#00AFBB\", high = \"#E7B800\")+theme_bw()+ggtitle('MISSINGNESS')" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n", - "'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.\n" - ] - }, - { - "data": { - "image/png": "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IYoi0tLSwm2ZmZlobW2d8DFNTU145plnYDKZsGHDBo7kTmIm8XU4HMjKyoo4z+FwyNLPxWCm1zKvY3k4HA6sWrUq/HNmZiZGR0fhdrsTckfHeGe32/H9738fBoMBlZWV2Lp1a8Q0LZoZl8uF/v5+pKenRx3jtb04MSknxfh8vqgV5Hq9Hl6vN+b55eXlqKqqQnJyMjo6OvDqq69Cr9dj7dq1cnQ34cwkvjefq9fr4fP5IEkS55VPw0xizetYPrGuawDwer1MXOZZQUEBnnjiCVgsFjgcDrz22msQRRHbtm1TumsJKRgM4o033sC6detiJuW8thcnJuW0YF544YUJRwrz8vKwc+fOqKTF6/VOWOrpxrm5+fn52LhxIxobG5nMTECr1U47vjef6/V6odVqmZBP00xizetYPrGuawAsJ7cAblyonJmZiZqaGhw9epRJ+SyEQiG8+eabUKlU2LlzZ8xzeG0vTkzKacHs3bt30uM+nw+hUAj9/f2w2WwAxm9/xhoViEUQBLCi58RsNtu045ueno6enh7k5uZOeh7FNpNY34zX8cK5dl2vWbMGwPi/SVJSEkcSZcDrenYkScL+/fsxOjqKhx9+eMLpP7y2Fycu9CTFaLValJWVoa6uDj6fD21tbbh48SIqKytjnn/hwgV4PB5IkoSOjg7U19dHzKmjSDOJb2VlJY4dOwan0wmn04ljx45h3bp1CvQ6Mc0k1ryO5y4YDMLv90OSJEiSBL/fj2AwGHVeZWUlTp48id7eXng8HnzyySe8rmdourG+dOkSXC4XgPH5zgcPHuR1PQtvvfUWHA4HHnroIWg0mgnP47W9OHHzIFKU2+3Gvn370NLSAoPBgO3bt4drO7e2IkoxSQAAApJJREFUtuKll17C008/DQB4/fXX0dzcjEAgALPZjOrqamzatEnJ7se9ieJ7c2wlScKHH34YUad8x44dnL4yA9ONNa/juaurq8PBgwcj2mpqarB+/Xr8+Mc/xp/+6Z8iJSUFAHD06FEcOXKEtZxnabqxfv/993HmzBn4fD4kJSWhoqICNTU1XOg5A0NDQ/jRj34ElUoFUbw+Znr//fcjPz+f1/YSwKSciIiIiEhhnL5CRERERKQwJuVERERERApjUk5EREREpDAm5URERERECmNSTkRERESkMCblREREREQKY1JORERERKQwJuVERERERApjUk5EREREpDAm5URERERECmNSTkRERESkMCblREREREQKY1JORERERKQwJuVERERERApjUk5EREREpDAm5URERERECmNSTkRERESkMCblREREREQKY1JORERERKQwJuVERAmoubkZVqsVJ0+eBAB0dXUhPT0dBw4cULZjREQ0K4IkSZLSnSAiopn76U9/iueffx7Hjx/H7t27sXbtWvzwhz9UultERDQLTMqJiBLYrl27cOXKFQiCgM8//xw6nU7pLhER0Sxw+goRUQL71re+hXPnzuHJJ59kQk5ElMA4Uk5ElKBcLhcqKytRW1uLd999F2fPnoXValW6W0RENAtMyomIEtRjjz0Gl8uFX/7yl/ijP/ojDA0N4dVXX1W6W0RENAucvkJElID27duH9957D//2b/8GAHjuuedw8uRJ/OIXv1C4Z0RENBscKSciIiIiUhhHyomIiIiIFMaknIiIiIhIYUzKiYiIiIgUxqSciIiIiEhhTMqJiIiIiBTGpJyIiIiISGFMyomIiIiIFMaknIiIiIhIYUzKiYiIiIgU9v8BD9Jk7sAeeSMAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "date_data = result_to_plot.loc[result_to_plot['variable']=='shortdate']\n", - "from ggplot import *\n", - "ggplot(aes(x = 'x', y='y',color = 'value'), data = date_data)+geom_point(size =50, alpha = 0.8)+theme_bw()#+scale_color_manual(values = ['grey','brown','orange','mediumaquamarine','royalblue','orchid'])+ggtitle('DATE')\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.8.12" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/misc_data_exploration_peptides.ipynb b/project/misc_data_exploration_peptides.ipynb deleted file mode 100644 index adeaccdf8..000000000 --- a/project/misc_data_exploration_peptides.ipynb +++ /dev/null @@ -1,765 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "# Peptides" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "import os\n", - "import config\n", - "from config import erda_dumps\n", - "from vaep.analyzers import analyzers" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "import seaborn as sns\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from sklearn import preprocessing\n", - "from sklearn.decomposition import PCA" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "pd.options.display.max_columns = 100\n", - "pd.options.display.min_rows = 30" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Data file and other configurations:\n", - "\n", - "- [ ] file reader for peptide intensities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# FN_PEPTIDE_INTENSITIES = config.FOLDER_DATA / 'df_intensities_N07813_M01000'\n", - "# analysis = analyzers.AnalyzePeptides.from_csv(FN_PEPTIDE_INTENSITIES, index_col=0)\n", - "# INDEX_NAME = 'Sample ID'\n", - "# analysis.df.index.name = INDEX_NAME\n", - "\n", - "FN_PEPTIDE_INTENSITIES = erda_dumps.FN_PEPTIDES # config.FOLDER_DATA / 'df_intensities_peptides_wide_2017_2018_2019_2020_N05011_M42725.pkl'\n", - "analysis = analyzers.AnalyzePeptides.from_pickle(FN_PEPTIDE_INTENSITIES)\n", - "\n", - "peptides = analysis.df\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "analysis.df.iloc[:10, :10]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "X = analysis.df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "N_MIN_OBS = 10\n", - "mask_min_obsevation = X.notna().sum() >= N_MIN_OBS\n", - "mask_min_obsevation.sum()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cleaning step\n", - "\n", - "- remove fractionated samples (need to be re-run and added to the analysis)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "queries = set()\n", - "\n", - "def find_indices_containing_query(query):\n", - " mask = X.index.str.contains(query)\n", - " X_query = X.loc[mask].sort_index()\n", - " queries.add(query)\n", - " return X_query" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "X_frac = find_indices_containing_query('[Ff]rac')\n", - "X_frac.index" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def get_unique_stub(X:pd.Index):\n", - " # X_frac_unique = sorted(list(set())) # matches too much\n", - " ret = X.str.split('frac').str[0].str.rsplit('_', n=1).str[0]\n", - " return sorted(list(set(ret)))\n", - "\n", - "X_frac_unique = get_unique_stub(X_frac.index)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from functools import partial\n", - "import ipywidgets as widgets\n", - "\n", - "def show_fractions(stub:str, df):\n", - " subset = df[df.index.str.contains(stub)]\n", - " display(subset)\n", - " display(subset.notna().sum(axis=1))\n", - "\n", - "w_data = widgets.Dropdown(options=X_frac_unique, index=0)\n", - " \n", - "# show_fractions(stub=X_frac_unique[2], df=X_frac)\n", - "\n", - "show_fractions = partial(show_fractions, df=X_frac)\n", - "out_sel = widgets.interactive_output(show_fractions, {'stub': w_data})\n", - "widgets.VBox([w_data, out_sel])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- check for file names with `exp`. Some seem to be fractionated samples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "X_exp = find_indices_containing_query('_exp\\d_')\n", - "X_exp.index" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "assert find_indices_containing_query('[gG][pP][fF]').empty" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "find_indices_containing_query('[cC][vV]').index" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "remove singe fraction samples (need to be quantified as one)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "X.drop(labels=X_frac.index, inplace=True)\n", - "X.drop(labels=X_exp.index, inplace=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# should be part of analysis\n", - "mask_less_than_500 = X.notna().sum(axis=1) < 500\n", - "print(X.loc[mask_less_than_500].sort_index().notna().sum(axis=1).to_string()) #'samples_potentially_fractionated.txt'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "['concat', 'HpH', 'ingel']" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Peptitome is spares" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "def get_sorted_not_missing(X:pd.DataFrame):\n", - " \"\"\"Return a Dataframe with missing values. Order columns by degree of completness \n", - " over columns from variables least to most shared among observations.\"\"\"\n", - " X = X.notna().astype(int)\n", - " return X[X.mean().sort_values().index]\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false", - "tags": [] - }, - "outputs": [], - "source": [ - "%time not_missing = get_sorted_not_missing(X)\n", - "not_missing.iloc[:,-10:].describe()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "not_missing.iloc[:10,-10:]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false", - "tags": [] - }, - "outputs": [], - "source": [ - "grid_kws = {\"width_ratios\": (.9, .05), \"hspace\": 0.5}\n", - "N_MOST_COMMON_PEPTIDES = 300\n", - "data_to_visualize = not_missing.iloc[:, -N_MOST_COMMON_PEPTIDES:]\n", - "print(f\"Look at missingness pattern of {N_MOST_COMMON_PEPTIDES} most common peptides across sample.\\n\"\n", - " f\"Data matrix dimension used for printing: { data_to_visualize.shape}\" )\n", - "\n", - "fig_heatmap_missing, (axes_heatmap_missing, cbar_ax) = plt.subplots(1, 2, gridspec_kw=grid_kws, figsize=(12,8))\n", - "axes_heatmap_missing = sns.heatmap(data_to_visualize, \n", - " ax=axes_heatmap_missing,\n", - " cbar_ax=cbar_ax,\n", - " cbar_kws={\"orientation\": \"vertical\"})\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "White patches indicates that a peptide has been measured, black means it was not measured. Some samples (rows) have few of the most common peptides. This suggests to set a minimum of total peptides in a sample, which is common pratice. \n", - "\n", - "> An algorithm should work with the most common peptides and base it's inference capabilities after training on these." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false", - "tags": [] - }, - "outputs": [], - "source": [ - "# # This currently crashes if you want to have a pdf\n", - "from datetime import datetime\n", - "datetime_now = datetime.now()\n", - "\n", - "from vaep.plotting import _savefig\n", - "_savefig(fig_heatmap_missing, f'peptides_heatmap_missing_{datetime_now:%y%m%d}', folder=config.FIGUREFOLDER, pdf=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Sample stats" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "TYPE = 'peptides'\n", - "COL_NO_MISSING, COL_NO_IDENTIFIED = f'no_missing_{TYPE}', f'no_identified_{TYPE}'\n", - "COL_PROP_SAMPLES = 'prop_samples'\n", - "\n", - "def compute_stats_missing(X):\n", - " \"\"\"Dataset of repeated samples indicating if an observation\n", - " has the variables observed or missing x\\in\\{0,1\\}\"\"\"\n", - " sample_stats = X.index.to_frame(index=False).reset_index()\n", - " sample_stats.columns = ['SampleID_int', 'INDEX']\n", - " sample_stats.set_index('INDEX', inplace=True)\n", - " \n", - " sample_stats[COL_NO_IDENTIFIED] = X.sum(axis=1)\n", - " sample_stats[COL_NO_MISSING] = (X == 0).sum(axis=1)\n", - "\n", - " assert all(sample_stats[[COL_NO_IDENTIFIED, COL_NO_MISSING]].sum(axis=1) == X.shape[1])\n", - " sample_stats = sample_stats.sort_values(by=COL_NO_IDENTIFIED, ascending=False)\n", - " sample_stats[COL_PROP_SAMPLES] = np.array(range(1,len(sample_stats)+1)) / len(sample_stats)\n", - " return sample_stats\n", - "\n", - "sample_stats = compute_stats_missing(not_missing)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "sample_stats" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "fig_ident = sns.relplot(x='SampleID_int', y=COL_NO_IDENTIFIED, data=sample_stats) \n", - "fig_ident.set_axis_labels('Sample ID', f'Frequency of identified {TYPE}')\n", - "fig_ident.fig.suptitle(f'Frequency of identified {TYPE} by sample id', y=1.03)\n", - "_savefig(fig_ident, f'identified_{TYPE}_by_sample', folder=config.FIGUREFOLDER)\n", - "\n", - "fig_ident_dist = sns.relplot(x=COL_PROP_SAMPLES, y=COL_NO_IDENTIFIED, data=sample_stats)\n", - "fig_ident_dist.set_axis_labels('Proportion of samples (sorted by frequency)', f'Frequency of identified {TYPE}')\n", - "fig_ident_dist.fig.suptitle(f'Frequency of identified {TYPE} groups by sample id', y=1.03)\n", - "_savefig(fig_ident_dist, f'identified_{TYPE}_ordered', folder=config.FIGUREFOLDER)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "COL_NO_MISSING_PROP = COL_NO_MISSING + '_PROP'\n", - "sample_stats[COL_NO_MISSING_PROP]= sample_stats[COL_NO_MISSING] / float(X.shape[1])\n", - "\n", - "# from ggplot import *\n", - "# ggplot(aes(x='nan_proc'), data = nonnan) + geom_histogram(binwidth = 0.005) #+ ylim(0,0.025)\n", - "sns.set(style=\"darkgrid\")\n", - "g = sns.relplot(x='prop_samples', y=COL_NO_MISSING_PROP, data=sample_stats)\n", - "plt.subplots_adjust(top=0.9)\n", - "g.set_axis_labels(\"Proportion of samples (sorted by frequency)\", \"proportion missing\")\n", - "g.fig.suptitle(f'Proportion of missing {TYPE} ordered')\n", - "_savefig(g, \"proportion_proteins_missing\", folder=config.FIGUREFOLDER)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Look at sequences" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "class SequenceAnalyser():\n", - " \n", - " def __init__(self, sequences : pd.Series):\n", - " if not isinstance(sequences, pd.Series):\n", - " raise ValueError(\"Please provide a pandas.Series, not {}\".format(type(sequences)))\n", - " self.sequences = sequences\n", - " \n", - " def calc_counts(self,n_characters):\n", - " return self.sequences.str[:n_characters].value_counts()\n", - " \n", - " def length(self):\n", - " return self.sequences.str.len().sort_values()\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "sequences = SequenceAnalyser(analysis.df.columns.to_series())\n", - "sequences.length()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "import ipywidgets as w\n", - "w.interact(sequences.calc_counts, n_characters=w.IntSlider(value=4, min=1, max=55))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "sequences_p4 = sequences.calc_counts(4)\n", - "display(sequences_p4.head())\n", - "sequences_p4.loc[sequences_p4.isin(('CON_','REV_'))].sort_index()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "What to do when \n", - "\n", - "\n", - "```\n", - "AAAAAAAAAAGAAGGRGSGPGR\n", - "AAAAAAAAAAGAAGGRGSGPGRR\n", - "\n", - "AAAANSGSSLPLFDCPTWAGKPPPGLHLDVVK\n", - "AAAANSGSSLPLFDCPTWAGKPPPGLHLDVVKGDK\n", - "```\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Select Proteins" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Minumum required sample quality\n", - "First define the minum requirement of a sample to be kept in " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false", - "tags": [] - }, - "outputs": [], - "source": [ - "import ipywidgets as w\n", - "MIN_DEPTH_SAMPLE = int(X.shape[-1] * 0.25)\n", - "w_min_depth_sample = w.IntSlider(value=MIN_DEPTH_SAMPLE, min=0, max=max(sample_stats[COL_NO_IDENTIFIED]))\n", - "print(f'Minimum {TYPE} per sample observed:')\n", - "w_min_depth_sample" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false", - "tags": [] - }, - "outputs": [], - "source": [ - "mask_samples = sample_stats[COL_NO_IDENTIFIED] >= w_min_depth_sample.value\n", - "print(f\"Selected {mask_samples.sum()} samples\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Distribution of Intensity values\n", - "- comparing non-transformed to $\\log_{10}$ transformed" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false", - "tags": [] - }, - "outputs": [], - "source": [ - "from vaep.transform import log\n", - "from random import sample\n", - "sample = X.sample(axis=0).iloc[0]\n", - "sample_id = sample.name # int(sample_stats.loc[sample.index].SampleID_int)\n", - "print(\"Sample ID:\", sample_id)\n", - "sns.set(style=\"darkgrid\")\n", - "sample = sample.dropna()\n", - "fig, axes = plt.subplots(1,2, figsize=(10,3))\n", - "sns.distplot(sample, bins=100, ax=axes[0])\n", - "axes[0].set_title(\"Unnormalized distribution\")\n", - "\n", - "sample_log = np.log(sample) # natural logarithm, could also be base_2, base_10 logarithm\n", - "sns.distplot(sample_log, bins=100, ax=axes[1])\n", - "axes[1].set_title('log (ln) normalized distribution')\n", - "\n", - "_ = fig.suptitle(f\"Dynamic Range of measured intensities in sample {sample_id}\")\n", - "fig.tight_layout(rect=[0, 0.03, 1, 0.95])\n", - "_savefig(fig, 'distribution_peptides_sample_' + str(sample_id), folder=config.FIGUREFOLDER)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false", - "tags": [] - }, - "outputs": [], - "source": [ - "from vaep.transform import log\n", - "from random import sample\n", - "sample = X.sample(axis=1)\n", - "sample_id = sample.columns[0]\n", - "print(\"Sample ID:\", sample_id)\n", - "sns.set(style=\"darkgrid\")\n", - "sample = sample.dropna()\n", - "fig, axes = plt.subplots(1,2, figsize=(10,3))\n", - "sns.distplot(sample, bins=100, ax=axes[0])\n", - "axes[0].set_title(\"Unnormalized distribution\")\n", - "\n", - "sample_log = np.log2(sample) # natural logarithm, could also be base_2, base_10 logarithm\n", - "sns.distplot(sample_log, bins=100, ax=axes[1])\n", - "axes[1].set_title('log (ln) normalized distribution')\n", - "\n", - "fig.suptitle(f\"Dynamic range of {sample_id} between samples\")\n", - "fig.tight_layout(rect=[0, 0.03, 1, 0.95])\n", - "_savefig(fig, 'distribution_peptides_sample_' + str(sample_id), folder=config.FIGUREFOLDER)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Reference table intensities (natural logarithm)\n", - "\n", - "14 to 23 spans a dynamic range of 3 orders of base 10" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "dynamic_range = pd.DataFrame(range(14, 24), columns=['x'])\n", - "dynamic_range['$e^x$'] = dynamic_range.x.apply(np.exp)\n", - "dynamic_range.set_index('x', inplace=True)\n", - "dynamic_range.index.name = ''\n", - "dynamic_range.T" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Next UP" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Find Protein of Peptides\n", - "- check with some reference list of peptides: This is created in `project\\FASTA_tryptic_digest.ipynb` " - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13 (default, Mar 28 2022, 06:59:08) [MSC v.1916 64 bit (AMD64)]" - }, - "nbdime-conflicts": { - "local_diff": [ - { - "diff": [ - { - "diff": [ - { - "diff": [ - { - "key": 4, - "op": "addrange", - "valuelist": "5" - }, - { - "key": 4, - "length": 1, - "op": "removerange" - } - ], - "key": 0, - "op": "patch" - } - ], - "key": "version", - "op": "patch" - } - ], - "key": "language_info", - "op": "patch" - } - ], - "remote_diff": [ - { - "diff": [ - { - "diff": [ - { - "key": 0, - "length": 1, - "op": "removerange" - } - ], - "key": "version", - "op": "patch" - } - ], - "key": "language_info", - "op": "patch" - } - ] - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/misc_data_exploration_proteins.ipynb b/project/misc_data_exploration_proteins.ipynb deleted file mode 100644 index faf1fe18e..000000000 --- a/project/misc_data_exploration_proteins.ipynb +++ /dev/null @@ -1,2133 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "# Denoising proteomics - data exploration" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "import os\n", - "from config import FN_PROTEIN_TSV \n", - "from config import FOLDER_DATA, FIGUREFOLDER" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "import seaborn as sns\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from sklearn import preprocessing\n", - "from sklearn.decomposition import PCA" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "import os\n", - "import logging\n", - "logger = logging.getLogger()\n", - "def _savefig(fig, name, folder=FIGUREFOLDER, pdf=True):\n", - " \"\"\"Save matplotlib Figure (having method `savefig`) as pdf and png.\"\"\"\n", - " filename = os.path.join(folder, name)\n", - " fig.savefig(filename + '.png')\n", - " if pdf: fig.savefig(filename + '.pdf')\n", - " logger.info(f\"Saved Figures to {filename}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "#coverage\n", - "def coverage(X:pd.DataFrame, coverage_col:float, coverage_row:float):\n", - " \"\"\"Select proteins by column depending on their coverage. \n", - " Of these selected proteins, where the rows have a certain number of overall proteins.\n", - " \"\"\"\n", - " mask_col = X.isnull().mean() <= 1-coverage_col\n", - " df = X.loc[:,mask_col]\n", - " mask_row = df.isnull().mean(axis=1) <= 1-coverage_row\n", - " df = df.loc[mask_row,:]\n", - " return df" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false", - "toc-hr-collapsed": false - }, - "source": [ - "## Load Data" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "df = pd.read_table(FN_PROTEIN_TSV, sep = '\\t')\n", - "df.sort_values(by = ['Date'], inplace = True)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "Collapsed": "false" - }, - "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", - "
indexDateMS_instrumentLCPIDColumnLengthA0A024QZ33A0A024QZ42A0A024QZP7A0A024QZX5...X6RK76X6RK96X6RKB4X6RKL2X6RKY7X6RLL4X6RLN4X6RLR1X6RLX0X6RM59
40820180713_QE8_nLC5_ASD_QC_Hela1_proteinGroups.txt20180713QE8nLC5ASDNaN46239000.0NaNNaN2.586900e+09...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
31220180713_QE8_nLC5_ASD_QC_Hela2_proteinGroups.txt20180713QE8nLC5ASDNaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
28120180713_QE8_nLC5_ASD_QC_Hela2_20190226172112_...20180713QE8nLC5ASDNaNNaNNaNNaN3.078800e+09...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
8220190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_02_pro...20190103QE8nLC0LiNi15.0NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
16120190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_01_pro...20190103QE8nLC0LiNi15.0NaNNaNNaN6.685000e+08...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", - "

5 rows × 25433 columns

\n", - "
" - ], - "text/plain": [ - " index Date \\\n", - "408 20180713_QE8_nLC5_ASD_QC_Hela1_proteinGroups.txt 20180713 \n", - "312 20180713_QE8_nLC5_ASD_QC_Hela2_proteinGroups.txt 20180713 \n", - "281 20180713_QE8_nLC5_ASD_QC_Hela2_20190226172112_... 20180713 \n", - "82 20190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_02_pro... 20190103 \n", - "161 20190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_01_pro... 20190103 \n", - "\n", - " MS_instrument LC PID ColumnLength A0A024QZ33 A0A024QZ42 \\\n", - "408 QE8 nLC5 ASD NaN 46239000.0 NaN \n", - "312 QE8 nLC5 ASD NaN NaN NaN \n", - "281 QE8 nLC5 ASD NaN NaN NaN \n", - "82 QE8 nLC0 LiNi 15.0 NaN NaN \n", - "161 QE8 nLC0 LiNi 15.0 NaN NaN \n", - "\n", - " A0A024QZP7 A0A024QZX5 ... X6RK76 X6RK96 X6RKB4 X6RKL2 X6RKY7 \\\n", - "408 NaN 2.586900e+09 ... NaN NaN NaN NaN NaN \n", - "312 NaN NaN ... NaN NaN NaN NaN NaN \n", - "281 NaN 3.078800e+09 ... NaN NaN NaN NaN NaN \n", - "82 NaN NaN ... NaN NaN NaN NaN NaN \n", - "161 NaN 6.685000e+08 ... NaN NaN NaN NaN NaN \n", - "\n", - " X6RLL4 X6RLN4 X6RLR1 X6RLX0 X6RM59 \n", - "408 NaN NaN NaN NaN NaN \n", - "312 NaN NaN NaN NaN NaN \n", - "281 NaN NaN NaN NaN NaN \n", - "82 NaN NaN NaN NaN NaN \n", - "161 NaN NaN NaN NaN NaN \n", - "\n", - "[5 rows x 25433 columns]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "# import datetime \n", - "# pd.to_datetime(df[\"Date\"],format='%Y%m%d') == datetime.datetime(2019, 4, 22)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Separate Data into proteome and meta-data" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "labels = df.iloc[:,0:6]\n", - "labels['shortdate']=labels['Date'].astype(str).str[:6]\n", - "X = df.iloc[:,6:] # ToDo: Rename everything from x to X -> code can be (potentially) copy-pasted\n", - "X.columns.name = 'proteins'" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "Collapsed": "false" - }, - "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", - "
proteinsA0A024QZ33A0A024QZ42A0A024QZP7A0A024QZX5A0A024R161A0A024R1R8A0A024R341A0A024R368A0A024R3B9A0A024R3M2...X6RK76X6RK96X6RKB4X6RKL2X6RKY7X6RLL4X6RLN4X6RLR1X6RLX0X6RM59
40846239000.0NaNNaN2.586900e+09NaN7.753100e+08210280000.0NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
312NaNNaNNaNNaNNaNNaNNaNNaN3154400.0NaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
281NaNNaNNaN3.078800e+09NaN1.238300e+09225030000.0NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
82NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
161NaNNaNNaN6.685000e+08NaNNaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", - "

5 rows × 25427 columns

\n", - "
" - ], - "text/plain": [ - "proteins A0A024QZ33 A0A024QZ42 A0A024QZP7 A0A024QZX5 A0A024R161 \\\n", - "408 46239000.0 NaN NaN 2.586900e+09 NaN \n", - "312 NaN NaN NaN NaN NaN \n", - "281 NaN NaN NaN 3.078800e+09 NaN \n", - "82 NaN NaN NaN NaN NaN \n", - "161 NaN NaN NaN 6.685000e+08 NaN \n", - "\n", - "proteins A0A024R1R8 A0A024R341 A0A024R368 A0A024R3B9 A0A024R3M2 ... \\\n", - "408 7.753100e+08 210280000.0 NaN NaN NaN ... \n", - "312 NaN NaN NaN 3154400.0 NaN ... \n", - "281 1.238300e+09 225030000.0 NaN NaN NaN ... \n", - "82 NaN NaN NaN NaN NaN ... \n", - "161 NaN NaN NaN NaN NaN ... \n", - "\n", - "proteins X6RK76 X6RK96 X6RKB4 X6RKL2 X6RKY7 X6RLL4 X6RLN4 X6RLR1 \\\n", - "408 NaN NaN NaN NaN NaN NaN NaN NaN \n", - "312 NaN NaN NaN NaN NaN NaN NaN NaN \n", - "281 NaN NaN NaN NaN NaN NaN NaN NaN \n", - "82 NaN NaN NaN NaN NaN NaN NaN NaN \n", - "161 NaN NaN NaN NaN NaN NaN NaN NaN \n", - "\n", - "proteins X6RLX0 X6RM59 \n", - "408 NaN NaN \n", - "312 NaN NaN \n", - "281 NaN NaN \n", - "82 NaN NaN \n", - "161 NaN NaN \n", - "\n", - "[5 rows x 25427 columns]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "X.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "Collapsed": "false" - }, - "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", - "
indexDateMS_instrumentLCPIDColumnLengthshortdate
40820180713_QE8_nLC5_ASD_QC_Hela1_proteinGroups.txt20180713QE8nLC5ASDNaN201807
31220180713_QE8_nLC5_ASD_QC_Hela2_proteinGroups.txt20180713QE8nLC5ASDNaN201807
28120180713_QE8_nLC5_ASD_QC_Hela2_20190226172112_...20180713QE8nLC5ASDNaN201807
8220190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_02_pro...20190103QE8nLC0LiNi15.0201901
16120190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_01_pro...20190103QE8nLC0LiNi15.0201901
\n", - "
" - ], - "text/plain": [ - " index Date \\\n", - "408 20180713_QE8_nLC5_ASD_QC_Hela1_proteinGroups.txt 20180713 \n", - "312 20180713_QE8_nLC5_ASD_QC_Hela2_proteinGroups.txt 20180713 \n", - "281 20180713_QE8_nLC5_ASD_QC_Hela2_20190226172112_... 20180713 \n", - "82 20190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_02_pro... 20190103 \n", - "161 20190103_QE8_nLC0_LiNi_QC_MNT_15cm_Hela_01_pro... 20190103 \n", - "\n", - " MS_instrument LC PID ColumnLength shortdate \n", - "408 QE8 nLC5 ASD NaN 201807 \n", - "312 QE8 nLC5 ASD NaN 201807 \n", - "281 QE8 nLC5 ASD NaN 201807 \n", - "82 QE8 nLC0 LiNi 15.0 201901 \n", - "161 QE8 nLC0 LiNi 15.0 201901 " - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "labels.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false", - "toc-hr-collapsed": false - }, - "source": [ - "### Proteome is sparse\n", - "Proteins that are only identified for a minority of samples should be removed" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "missingness = X.notnull().astype('int')\n", - "missingness = missingness[missingness.mean().sort_values().index]\n", - "missingness.index.name = 'SampleID'\n", - "missingness_index_id = missingness.index.to_frame()\n", - "missingness_index_id[\"DateID\"] = labels.Date\n", - "missingness.index = labels.Date\n", - "missingness.sort_index(inplace=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "grid_kws = {\"width_ratios\": (.9, .05), \"hspace\": 0.5}\n", - "fig_heatmap_missing, (axes_heatmap_missing, cbar_ax) = plt.subplots(1, 2, gridspec_kw=grid_kws, figsize=(12,8))\n", - "axes_heatmap_missing = sns.heatmap(missingness, ax=axes_heatmap_missing,\n", - " cbar_ax=cbar_ax,\n", - " cbar_kws={\"orientation\": \"vertical\"})" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "# # This currently crashes if you want to have a pdf\n", - "_savefig(fig_heatmap_missing, 'proteins_heatmap_missing', pdf=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "#### Samples have 6 to 4461 identified protein-groups\n", - "- cutoff for minimum quality of peptide, e.g. at least 2500 identified proteins?\n", - "- Proteome is not consistent over many runs" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "Collapsed": "false" - }, - "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", - "
SampleIDDateno_identified_proteinsno_missing_proteins_of_proteomeprop_samples
0408201907124461209660.002114
1312201907124437209900.004228
2281201909024304211230.006342
382201909104292211350.008457
4161201907084281211460.010571
..................
4684072019030616254110.991543
469712019030310254170.993658
47012201904139254180.995772
471375201907028254190.997886
47233201909066254211.000000
\n", - "

473 rows × 5 columns

\n", - "
" - ], - "text/plain": [ - " SampleID Date no_identified_proteins \\\n", - "0 408 20190712 4461 \n", - "1 312 20190712 4437 \n", - "2 281 20190902 4304 \n", - "3 82 20190910 4292 \n", - "4 161 20190708 4281 \n", - ".. ... ... ... \n", - "468 407 20190306 16 \n", - "469 71 20190303 10 \n", - "470 12 20190413 9 \n", - "471 375 20190702 8 \n", - "472 33 20190906 6 \n", - "\n", - " no_missing_proteins_of_proteome prop_samples \n", - "0 20966 0.002114 \n", - "1 20990 0.004228 \n", - "2 21123 0.006342 \n", - "3 21135 0.008457 \n", - "4 21146 0.010571 \n", - ".. ... ... \n", - "468 25411 0.991543 \n", - "469 25417 0.993658 \n", - "470 25418 0.995772 \n", - "471 25419 0.997886 \n", - "472 25421 1.000000 \n", - "\n", - "[473 rows x 5 columns]" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "COL_NO_MISSING_PROT, COL_NO_IDENTIFIED_PROT ='no_missing_proteins_of_proteome', 'no_identified_proteins'\n", - "COL_PROP_SAMPLES = 'prop_samples'\n", - "\n", - "sample_stats = missingness.sum(axis=1).to_frame(COL_NO_IDENTIFIED_PROT)\n", - "sample_stats[COL_NO_MISSING_PROT] = (missingness == 0).sum(axis=1)\n", - "\n", - "assert all(sample_stats.sum(axis=1) == X.shape[1])\n", - "sample_stats = sample_stats.sort_values(by=COL_NO_IDENTIFIED_PROT, ascending=False).reset_index()\n", - "sample_stats[COL_PROP_SAMPLES] = np.array(range(1,len(sample_stats)+1)) / len(sample_stats)\n", - "sample_stats = sample_stats.set_index(missingness_index_id.SampleID)\n", - "sample_stats.reset_index(inplace=True)\n", - "sample_stats" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "fig_ident_prot = sns.relplot(x='SampleID', y=COL_NO_IDENTIFIED_PROT, data=sample_stats) \n", - "fig_ident_prot.set_axis_labels(\"Sample ID\", \"Frequency of identified proteins\")\n", - "fig_ident_prot.fig.suptitle('Frequency of identified protein groups by sample id', y=1.03)\n", - "_savefig(fig_ident_prot, 'identified_proteins_by_sample')\n", - "\n", - "fig_ident_prot_dist = sns.relplot(x=COL_PROP_SAMPLES, y=COL_NO_IDENTIFIED_PROT, data=sample_stats)\n", - "fig_ident_prot_dist.set_axis_labels(\"Proportion of samples (sorted by frequency)\", \"Frequency of identified proteins\")\n", - "fig_ident_prot_dist.fig.suptitle('Frequency of identified protein groups by sample id', y=1.03)\n", - "_savefig(fig_ident_prot_dist, 'identified_proteins_ordered')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Protein-Groups do not match well\n", - "- Are the assigned protein-group names sensible inbetween runs? \n", - " > Each sample has at least 80 percent missing values regarding all identified proteins\n", - "- Clustering by MaxQuant into protein-groups is sample dependent and therefore some groups might represent a very similar set of peptides" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "image/png": "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V5588knnPYGBgYwaNQpd11FK8a9//YvRo0fTs2dPAB577DG++eYb3nzzTaesK6+8ksmTJ6PrOo0bNyYpKYl3332Xdu3aMX/+fPr3788f/vAHABo2bMj+/ft57bXXuOOOOwC49tprnb7lgjrYtk1ERMRZMZSlvICAACZPnozH46FRo0a8++677N69m+7du593eTVr1gQoti4FfD4fkydPpnbt2jRq1IgZM2bQo0cPpz49e/bk008/Peu6X375BV3XufLKK7nyyisZPHgwDRs25IorruCnn37C5/NRr14953ydOnVo2LBhsXU4V8wLFixg4MCB3HfffQBMmTKF7du3lxhPXFwcixYtYuzYsQCsWbOGrl27EhwcTGBgIM8++6xT1pVXXsmdd97JgQMHSiyvJJ9//jl79+7lnXfecb5lzZw5k06dOrFv375z3p8z7du3j23btvH+++8THR3tlNWlSxcSExPp378/AAMGDOC6664DYPHixbjdbiZNmoTb7aZx48Z8++23fPbZZwB89NFHuN1uJk+ejKZpNGrUiL/97W8MHjyYv/zlL85njxo1imuuuQaAcePGERcXx6BBgwC45ppr+PHHH3nrrbfo2bMn7733HnfeeSeDBw8GYPz48WzduvW8793lqlol3FGjRtGrVy8A3G43derUcf6iF7jqqqvQ9fyeluPHj5Oenk6rVq2KvOfmm29m7dq1znHr1q2dawBiYmKcr58HDhxg6NChZ13/8ccfO8cFf1nLoizl1a9fv0hcISEh+Hy+Cy6vNCEhIdSuXds5DggI4Oqrry5yXNzXxttvv52bbrqJ3r17c91113HHHXfQp08fatasyfXXX09cXBzDhw/n6quv5o477qB3797UqVOn2DqcK+a9e/fy4IMPOufcbjctWrQoMZ4ePXrw/PPP8/3339O4cWM2bNjAzJkzAbjhhhsIDAzkf//3fzl06BAHDx5k//793HzzzWW8W6cdOHCAnJycYkc1/PDDD3Tu3LnE+1NcWW63mxtvvNF5LTg4mBtuuIH9+/c7rxX+uezfv59mzZrhdrud12JiYpyEe+DAAY4ePcpNN93knFdKYds2hw8fdl4r/Pd3//797Nu3r8jfH9M0nQec+/fvd/4NAmia5vyCqA6qVcINDw+nQYMG53xPQECA8/+BgYHFvqfgL10BwzCKnLdt20nAxZVx5vUlfU5xylJe4X9Al6K80hQ3WqDwL6Bzffa8efP473//y6effsqmTZt45513eP3112nfvj0zZ85k+PDhbNy4kc2bN7N48WKmTZvmtC4LO1fMLpfrvOKpU6cO7du3Z82aNbRs2RLDMLjtttsA2LZtGyNHjqRnz57ccsstDB06lA8//JC9e/eeVU5xDwYL9yubpkn9+vWZN2/eWe+rXbt2qfensMJ/bwtTShV5CHvmz1ud8YC28H00TZNWrVoxffr0s8qtW7cu33zzzVmfbVkWDz30EAMHDiy2PiV95rmeMVQl1f6h2bmEhIQQGRnJ119/XeT1r776ikaNGjnH3333XZHzO3fupHnz5gA0atSo1OvPdK4n+BdS3rlc6vLOxxdffMHcuXO5+eabefLJJ/noo4+44YYbWLduHXv27GH69Olcf/31/PnPf2bZsmXce++959XyLnDdddexe/du59iyLL7//vtzXhMbG8u///1vPvnkE+69917nl8p7771Hjx49mDFjBoMGDSImJoYjR46clUTgdPIq/BCs4OEhQOPGjTl27Bg1atSgQYMGNGjQALfbzfPPP09aWto578+ZGjdujM/nY9euXc5rOTk57Nmzh2uvvbbYGAseDhb+9lH473Ljxo05cuQIUVFRTv1OnDjBrFmzSvzGVHBNwfsbNGhAUlISixcvdj6zIFEX95lVnSTcUowcOZLXXnuNjz/+mMOHD/Pqq6/y2Wef8dBDDznv+e6775g9ezY//PAD8+bNY+vWrc75kSNHsnTpUhYvXszhw4d59913ef/99xkyZEiJnxkcHMzPP//Mzz//XGx9zre80uK7lOWdj6CgIP7xj3+wdOlSfv75Z7Zu3cqhQ4eIjo6mVq1avPvuu/zjH//g6NGj/Oc//+Hrr7++oK+fQ4cOZcmSJaxatYpDhw7x7LPP8vPPP5/zF9vdd9/N0aNHWbduHbGxsc7rYWFh7Ny5k927d/PDDz8we/ZstmzZUmyXSZ06dahXrx5z587lxx9/5JNPPmH58uXO+dtuu43rrruOsWPHsmvXLvbs2cNTTz3F0aNHufLKK895f87UsGFDunXrxtNPP82OHTvYt28f48aNwzAM5/nDmXr27Imu60ycOJGDBw+SmJjIsmXLnPO9evVC13XGjRvHvn37+Oqrrxg/fjzZ2dmEhoYWW+awYcPYtGkTr732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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "COL_NO_MISSING_PROT_PROP = COL_NO_MISSING_PROT + '_PROP'\n", - "sample_stats[COL_NO_MISSING_PROT_PROP]= sample_stats[COL_NO_MISSING_PROT] / float(X.shape[1])\n", - "\n", - "# from ggplot import *\n", - "# ggplot(aes(x='nan_proc'), data = nonnan) + geom_histogram(binwidth = 0.005) #+ ylim(0,0.025)\n", - "sns.set(style=\"darkgrid\")\n", - "g = sns.relplot(x='prop_samples', y=COL_NO_MISSING_PROT_PROP, data=sample_stats)\n", - "plt.subplots_adjust(top=0.9)\n", - "g.set_axis_labels(\"Proportion of samples (sorted by frequency)\", \"proportion missing\")\n", - "g.fig.suptitle('Proportion of missing values ordered')\n", - "_savefig(g, \"proportion_proteins_missing.pdf\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Protein-Groups" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "protein_groups = X.columns.to_frame('proteins')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "Some protein groups are ensembles?" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "proteins\n", - "X6RM59 6\n", - "K7EQF5 6\n", - "K7EQG1 6\n", - "K7EQG9 6\n", - "K7EQH1 6\n", - " ..\n", - "CON__ENSEMBL:ENSBTAP00000024462 31\n", - "CON__ENSEMBL:ENSBTAP00000032840 31\n", - "CON__ENSEMBL:ENSBTAP00000038329 31\n", - "CON__ENSEMBL:ENSBTAP00000001528 31\n", - "CON__ENSEMBL:ENSBTAP00000018229 31\n", - "Name: proteins, Length: 25427, dtype: int64" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "protein_groups.proteins.str.len().sort_values()" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Top 24 grouped by first characters\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "ce9bfeb6c8e34b8493d15e92a20bf337", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "interactive(children=(IntSlider(value=4, description='n_characters', max=10, min=1), Output()), _dom_classes=(…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import ipywidgets as w\n", - "N=24\n", - "print(f'Top {N} grouped by first characters')\n", - "def calc_counts(n_characters):\n", - " return protein_groups.proteins.str[:n_characters].value_counts()[:N]\n", - "w.interact(calc_counts, n_characters=w.IntSlider(value=4, min=1, max=10))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "How does the naming work?" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "protein_groups['p4'] = protein_groups.proteins.str[:4]\n", - "protein_groups['p8'] = protein_groups.proteins.str[:8]\n", - "protein_groups['p9'] = protein_groups.proteins.str[:9]" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "Collapsed": "false" - }, - "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", - "
proteinsp4p8p9
proteins
A0A024QZ33A0A024QZ33A0A0A0A024QZA0A024QZ3
A0A024QZ42A0A024QZ42A0A0A0A024QZA0A024QZ4
A0A024QZP7A0A024QZP7A0A0A0A024QZA0A024QZP
A0A024QZX5A0A024QZX5A0A0A0A024QZA0A024QZX
A0A024R161A0A024R161A0A0A0A024R1A0A024R16
...............
X6RLL4X6RLL4X6RLX6RLL4X6RLL4
X6RLN4X6RLN4X6RLX6RLN4X6RLN4
X6RLR1X6RLR1X6RLX6RLR1X6RLR1
X6RLX0X6RLX0X6RLX6RLX0X6RLX0
X6RM59X6RM59X6RMX6RM59X6RM59
\n", - "

25427 rows × 4 columns

\n", - "
" - ], - "text/plain": [ - " proteins p4 p8 p9\n", - "proteins \n", - "A0A024QZ33 A0A024QZ33 A0A0 A0A024QZ A0A024QZ3\n", - "A0A024QZ42 A0A024QZ42 A0A0 A0A024QZ A0A024QZ4\n", - "A0A024QZP7 A0A024QZP7 A0A0 A0A024QZ A0A024QZP\n", - "A0A024QZX5 A0A024QZX5 A0A0 A0A024QZ A0A024QZX\n", - "A0A024R161 A0A024R161 A0A0 A0A024R1 A0A024R16\n", - "... ... ... ... ...\n", - "X6RLL4 X6RLL4 X6RL X6RLL4 X6RLL4\n", - "X6RLN4 X6RLN4 X6RL X6RLN4 X6RLN4\n", - "X6RLR1 X6RLR1 X6RL X6RLR1 X6RLR1\n", - "X6RLX0 X6RLX0 X6RL X6RLX0 X6RLX0\n", - "X6RM59 X6RM59 X6RM X6RM59 X6RM59\n", - "\n", - "[25427 rows x 4 columns]" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "protein_groups.sort_values('p8')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "Prefixed `CON__` or `REV__`" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "Collapsed": "false" - }, - "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", - "
proteinsp4p8p9
proteins
CON__A2I7N0CON__A2I7N0CON_CON__A2ICON__A2I7
CON__A2I7N1CON__A2I7N1CON_CON__A2ICON__A2I7
CON__A2I7N3CON__A2I7N3CON_CON__A2ICON__A2I7
CON__ENSEMBL:ENSBTAP00000001528CON__ENSEMBL:ENSBTAP00000001528CON_CON__ENSCON__ENSE
CON__ENSEMBL:ENSBTAP00000006074CON__ENSEMBL:ENSBTAP00000006074CON_CON__ENSCON__ENSE
...............
REV__Q96HY6REV__Q96HY6REV_REV__Q96REV__Q96H
REV__Q96HY6-2REV__Q96HY6-2REV_REV__Q96REV__Q96H
REV__Q96PE2REV__Q96PE2REV_REV__Q96REV__Q96P
REV__Q9BYP7-4REV__Q9BYP7-4REV_REV__Q9BREV__Q9BY
REV__Q9Y2X3REV__Q9Y2X3REV_REV__Q9YREV__Q9Y2
\n", - "

84 rows × 4 columns

\n", - "
" - ], - "text/plain": [ - " proteins p4 \\\n", - "proteins \n", - "CON__A2I7N0 CON__A2I7N0 CON_ \n", - "CON__A2I7N1 CON__A2I7N1 CON_ \n", - "CON__A2I7N3 CON__A2I7N3 CON_ \n", - "CON__ENSEMBL:ENSBTAP00000001528 CON__ENSEMBL:ENSBTAP00000001528 CON_ \n", - "CON__ENSEMBL:ENSBTAP00000006074 CON__ENSEMBL:ENSBTAP00000006074 CON_ \n", - "... ... ... \n", - "REV__Q96HY6 REV__Q96HY6 REV_ \n", - "REV__Q96HY6-2 REV__Q96HY6-2 REV_ \n", - "REV__Q96PE2 REV__Q96PE2 REV_ \n", - "REV__Q9BYP7-4 REV__Q9BYP7-4 REV_ \n", - "REV__Q9Y2X3 REV__Q9Y2X3 REV_ \n", - "\n", - " p8 p9 \n", - "proteins \n", - "CON__A2I7N0 CON__A2I CON__A2I7 \n", - "CON__A2I7N1 CON__A2I CON__A2I7 \n", - "CON__A2I7N3 CON__A2I CON__A2I7 \n", - "CON__ENSEMBL:ENSBTAP00000001528 CON__ENS CON__ENSE \n", - "CON__ENSEMBL:ENSBTAP00000006074 CON__ENS CON__ENSE \n", - "... ... ... \n", - "REV__Q96HY6 REV__Q96 REV__Q96H \n", - "REV__Q96HY6-2 REV__Q96 REV__Q96H \n", - "REV__Q96PE2 REV__Q96 REV__Q96P \n", - "REV__Q9BYP7-4 REV__Q9B REV__Q9BY \n", - "REV__Q9Y2X3 REV__Q9Y REV__Q9Y2 \n", - "\n", - "[84 rows x 4 columns]" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "protein_groups.loc[protein_groups.p4.isin(('CON_','REV_'))].sort_index()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false", - "toc-hr-collapsed": false - }, - "source": [ - "## Select Proteins" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Minumum required sample quality\n", - "First define the minum requirement of a sample to be kept in " - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "5652baf0957f48ef99021159aee75fe3", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "IntSlider(value=1500, max=4461)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import ipywidgets as w\n", - "MIN_DEPTH_SAMPLE = 1500\n", - "w_min_depth_sample = w.IntSlider(value=MIN_DEPTH_SAMPLE, min=0, max=max(sample_stats[COL_NO_IDENTIFIED_PROT]))\n", - "w_min_depth_sample" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Selected 413 samples\n" - ] - } - ], - "source": [ - "mask_samples = sample_stats[COL_NO_IDENTIFIED_PROT] >= w_min_depth_sample.value\n", - "print(f\"Selected {mask_samples.sum()} samples\")" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "# datasets with 50% and 90% coverage + log transformation, z-normalization and fill missingness (for pca)\n", - "x_50 = coverage(X.loc[mask_samples], coverage_col=0.5, coverage_row=0.2)\n", - "# x_50_pca = log_z_zeroone_na(x_50) # there is a huge difference if NA is set to low value or mean!!\n", - "x_90 = coverage(X.loc[mask_samples], 0.9, 0.9)\n", - "# x_90_pca = log_z_zeroone_na(x_90)" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": { - "Collapsed": "false" - }, - "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", - "
proteinsA0A075B736A0A087WYC1A0A0A0MSI0A0A0B4J2C3A0A0C4DGZ5A0A0J9YXZ5A0A140T936A0A2R8Y6G6A0A3B3IS95A0A494C1A5...Q9NYU2Q9UG63-2Q9UIG0Q9UQ80-2Q9Y265-2Q9Y2W1Q9Y3A5Q9Y3F4-2Q9Y617-2V9GYZ6
SampleID
82.257000e+094.630300e+101.383400e+112.232300e+101.554300e+104.390000e+102.025100e+102.889800e+111.090300e+113.493700e+10...2.272000e+091.636800e+108.111000e+095.147400e+101.253200e+107.201600e+095.729700e+091.356700e+101.721900e+105.427000e+10
\n", - "

1 rows × 147 columns

\n", - "
" - ], - "text/plain": [ - "proteins A0A075B736 A0A087WYC1 A0A0A0MSI0 A0A0B4J2C3 \\\n", - "SampleID \n", - "8 2.257000e+09 4.630300e+10 1.383400e+11 2.232300e+10 \n", - "\n", - "proteins A0A0C4DGZ5 A0A0J9YXZ5 A0A140T936 A0A2R8Y6G6 \\\n", - "SampleID \n", - "8 1.554300e+10 4.390000e+10 2.025100e+10 2.889800e+11 \n", - "\n", - "proteins A0A3B3IS95 A0A494C1A5 ... Q9NYU2 Q9UG63-2 \\\n", - "SampleID ... \n", - "8 1.090300e+11 3.493700e+10 ... 2.272000e+09 1.636800e+10 \n", - "\n", - "proteins Q9UIG0 Q9UQ80-2 Q9Y265-2 Q9Y2W1 \\\n", - "SampleID \n", - "8 8.111000e+09 5.147400e+10 1.253200e+10 7.201600e+09 \n", - "\n", - "proteins Q9Y3A5 Q9Y3F4-2 Q9Y617-2 V9GYZ6 \n", - "SampleID \n", - "8 5.729700e+09 1.356700e+10 1.721900e+10 5.427000e+10 \n", - "\n", - "[1 rows x 147 columns]" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x_90.sample()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "### Distribution of Intensity values\n", - "- comparing non-transformed to $\\log_{10}$ transformed" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": { - "Collapsed": "false" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Sample ID: 366\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsQAAADVCAYAAABQQOaUAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nOzdd3xUdfb4/9eUZNIrE0KTEiC00ERBqtRQEhBWXRuwUhQV+S27X1hBPgsirGvfFRYLFiygIoKaRZpiQxABkV5CCYQQ0nuZTLm/P8LMJpBkEjJhSs7z8cgjuXPv3Hvec+9Mztx77vutUhRFQQghhBBCiEZK7ewAhBBCCCGEcCZJiIUQQgghRKMmCbEQQgghhGjUJCEWQgghhBCNmiTEQgghhBCiUZOEWAghhBBCNGqSEAtRT8OGDeOuu+7CZDJVeryoqIjo6Gj27t3rpMiuN2zYMD766CMAVqxYwaRJkxpkOx999BHDhg1rkHXXpGL7GsqaNWt47bXX6ry9rVu3smDBgoYM7aZw1WOo4vKXLl0iOjqa06dP231ednY2CQkJNS4THR3Nd999B8DkyZN5/vnnax3XtYqKivjss89s00899RRz5sy54fUJIRxDEmIhHODEiROsWbPG2WHUybRp03jnnXecHYZbSU1N5YMPPmD69Ol1fu7o0aM5ffq0S31Bqi9XPYaaNWvGrl27aNeund1lX3zxRXbs2FHjMrt27WLAgAEOie29997j448/tk0//fTTLFu2zCHrFkLcOEmIhXCAFi1asHLlSi5duuTsUGrN39+f0NBQZ4fhVt5++21iY2Px9/e/oedPnjyZlStXOjgq53HVY0ij0aDX69FqtXaXrc3YVHq9Hm9vb0eEdt32AgMDCQoKcsi6hRA3ThJiIRxg8uTJNG/enCVLllS7jKIofPDBB8TGxhITE8OECRP44YcfKq1jyZIljBkzhjvuuIOzZ88ybNgwPv74Yx544AFiYmIYP348p0+fZsWKFfTt25d+/fqxevVq2zoyMzP561//Sr9+/ejWrRsjRoyodHm2ooqXuydPnkx0dPR1P5s2bQLg/PnzTJ8+nR49ejB06FBeeOEFysrKbOs6fPgw9957Lz169OChhx4iLS2t2tfhgQce4Lnnnqv02PLly5k2bRoAO3bsIC4ujpiYGIYNG8bbb79d7brsSUhIID4+nu7duxMbG2trj9VHH33EnXfeSc+ePZk3bx5//etfWbFiRZXrKioqYuPGjYwcObLK+StWrGD27Nk8//zz3H777QwcOJBly5ZhNpttywwdOpSDBw9y8uTJKtfx1FNPsWTJEhYsWECvXr0YNmwYq1atss2XY4haLX9tyUR1x9SKFSvYtGkT27ZtIzo6GigvCXnhhRe48847GTJkCHl5eZVKJqC8zGLGjBnExMQwduxYfvnll0r74NqSCuvzN27cyMqVKzl27BjR0dFcunTpupKJXbt2cc8999CzZ0+GDh3K22+/bUuiN27cyKRJk1i9ejUDBw6kb9++/L//9/8oLi6u8bUSQtgnCbEQDuDl5cXSpUvZtWsXmzdvrnKZN954gxUrVjBnzhy++uorRowYwWOPPVYpOdqwYQMLFy7kzTffJCoqCoB//etfTJs2jS+++AKNRsNDDz1ESkoK69at4+GHH+bll1/mwoULAPztb38jOzubNWvWsHnzZoYNG8aSJUvIyMioMf4VK1awa9cu28/o0aNp06YNI0eOxGAwMH36dFq1asWmTZt44YUX+Omnn2yXeXNzc5k5cyadOnVi48aNTJgwocbykbi4OLZu3Wr7J2+xWNi6dSvx8fFkZmYyd+5cpk6dytatW5k/fz7/+te/2LNnT633hdVXX33FggULuP/++/nqq6+YPHky//d//8f3338PwObNm3nxxRf585//zOeff45Wq6123wHs27cPjUZDr169ql3m+++/Jz8/n08++YQ5c+awdu1avvnmG9v84OBgYmJi+PHHH6tdx4YNG2jatCmff/45d999N//+9785evQoIMeQVV2Wr+mYmjZtGmPGjGHo0KHs2rXL9pzPPvuM1157jZUrVxIcHHzdOr/44gv69OnDl19+yciRI5kxYwbJyck1vj4AY8eOZdq0aXTq1Ildu3bRrFmzSvP37dvHI488wtChQ9m0aRNz585l1apVrFu3zrbM6dOnOXDgAO+99x7Lli1jx44dfPLJJ3a3LYSomSTEQjhInz59uOeee/jHP/5BXl5epXmKovD+++8za9Ysxo0bR9u2bXnyySfp379/pbNzffv2ZdCgQXTv3t322NixYxkxYgRRUVGMHTuW4uJilixZQlRUFDNmzEClUnH27FkAhgwZwtKlS+nUqROtW7fmscce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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from vaep.transform import log\n", - "from random import sample\n", - "sample = x_50.sample()\n", - "sample_id = sample.index[0]\n", - "print(\"Sample ID:\", sample_id)\n", - "sns.set(style=\"darkgrid\")\n", - "fig, axes = plt.subplots(1,2, figsize=(10,3))\n", - "sns.distplot(sample, bins=100, ax=axes[0])\n", - "sample_log = log(sample) # natural logarithm, could also be base_2, base_10 logarithm\n", - "sns.distplot(sample_log, bins=100, ax=axes[1])\n", - "_ = fig.suptitle(\"Normalized vs. log (ln) normalized distribution\")\n", - "plt.tight_layout()\n", - "_savefig(fig, 'distribution_sample_' + str(sample_id))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "ToDo: Select a logarithm for the transformation which is either interpretable or gives best to normal distribution:\n", - "1. $log_2$: Interpretable as continous doubling of the intensity\n", - "2. KDensity measure of goodness of fit to normal distribution." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "x_50 = x_50.apply(log)\n", - "x_90 = x_90.apply(log)" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": { - "Collapsed": "false" - }, - "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", - "
proteinsA0A075B6E2A0A075B6F9A0A075B6Q0A0A075B736A0A087WSY9A0A087WTB8A0A087WTW0A0A087WUC6A0A087WUE9A0A087WUZ3...U3KQ85V5IRT4V9GYP5V9GYY3V9GYZ6X6R8A1X6RA14X6RA30X6RAC9X6RFL8
SampleID
40823.30892220.59128818.53392023.16108122.94706720.54162420.20455920.24031520.73795723.491972...19.93149118.11639521.10982023.61274823.45359920.90116121.53588419.92890520.952471NaN
28123.30029620.42208018.91592623.13371822.89925520.76938620.39777120.53468120.70705523.667126...19.51932617.81077121.16936123.75359323.71799820.95818021.89395119.753284NaNNaN
8222.241750NaNNaN22.498286NaN19.45943718.80689518.96943819.87395622.474429...20.96393517.666934NaNNaN22.38143719.978657NaN18.560182NaNNaN
16122.241465NaNNaN22.683572NaN19.93314518.912018NaN19.67167122.149430...NaNNaN20.086215NaN22.41363819.699251NaN18.398496NaNNaN
25120.808342NaN18.82120022.698971NaN20.19363119.569891NaN20.333197NaN...NaN18.384494NaN23.11733622.46713020.543469NaN19.538115NaNNaN
\n", - "

5 rows × 1897 columns

\n", - "
" - ], - "text/plain": [ - "proteins A0A075B6E2 A0A075B6F9 A0A075B6Q0 A0A075B736 A0A087WSY9 \\\n", - "SampleID \n", - "408 23.308922 20.591288 18.533920 23.161081 22.947067 \n", - "281 23.300296 20.422080 18.915926 23.133718 22.899255 \n", - "82 22.241750 NaN NaN 22.498286 NaN \n", - "161 22.241465 NaN NaN 22.683572 NaN \n", - "251 20.808342 NaN 18.821200 22.698971 NaN \n", - "\n", - "proteins A0A087WTB8 A0A087WTW0 A0A087WUC6 A0A087WUE9 A0A087WUZ3 ... \\\n", - "SampleID ... \n", - "408 20.541624 20.204559 20.240315 20.737957 23.491972 ... \n", - "281 20.769386 20.397771 20.534681 20.707055 23.667126 ... \n", - "82 19.459437 18.806895 18.969438 19.873956 22.474429 ... \n", - "161 19.933145 18.912018 NaN 19.671671 22.149430 ... \n", - "251 20.193631 19.569891 NaN 20.333197 NaN ... \n", - "\n", - "proteins U3KQ85 V5IRT4 V9GYP5 V9GYY3 V9GYZ6 X6R8A1 \\\n", - "SampleID \n", - "408 19.931491 18.116395 21.109820 23.612748 23.453599 20.901161 \n", - "281 19.519326 17.810771 21.169361 23.753593 23.717998 20.958180 \n", - "82 20.963935 17.666934 NaN NaN 22.381437 19.978657 \n", - "161 NaN NaN 20.086215 NaN 22.413638 19.699251 \n", - "251 NaN 18.384494 NaN 23.117336 22.467130 20.543469 \n", - "\n", - "proteins X6RA14 X6RA30 X6RAC9 X6RFL8 \n", - "SampleID \n", - "408 21.535884 19.928905 20.952471 NaN \n", - "281 21.893951 19.753284 NaN NaN \n", - "82 NaN 18.560182 NaN NaN \n", - "161 NaN 18.398496 NaN NaN \n", - "251 NaN 19.538115 NaN NaN \n", - "\n", - "[5 rows x 1897 columns]" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x_50.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "Collapsed": "false" - }, - "source": [ - "## Imputing missing values in log-transformed space\n", - "\n", - "Options:\n", - "1. Mean Imputation\n", - "2. Zero Imputation\n", - "2. Shifted Mean Imputation (and randomization)" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "from vaep.imputation import imputation_normal_distribution\n", - "_manuael_imputed = imputation_normal_distribution(x_50.iloc[:,0])\n", - "_applied_imputed = x_50.iloc[:,:3].apply(imputation_normal_distribution).iloc[:,0]\n", - "assert _manuael_imputed.equals(_applied_imputed), \"You got apply wrong\"" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "from vaep.imputation import imputation_normal_distribution\n", - "x_50 = x_50.apply(imputation_normal_distribution)\n", - "x_90 = x_90.apply(imputation_normal_distribution)" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "from config import PROCESSED_DATA, PREFIX_IMPUTED, PREFIX_META\n", - "x_50.to_pickle(os.path.join(PROCESSED_DATA, PREFIX_IMPUTED+'_50.pkl'))\n", - "x_90.to_pickle(os.path.join(PROCESSED_DATA, PREFIX_IMPUTED+'_90.pkl'))" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [ - "labels.to_pickle(os.path.join(PROCESSED_DATA, PREFIX_META + '.pkl'))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "Collapsed": "false" - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13 (default, Mar 28 2022, 06:59:08) [MSC v.1916 64 bit (AMD64)]" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/misc_id_mapper.ipynb b/project/misc_id_mapper.ipynb deleted file mode 100644 index b549dd839..000000000 --- a/project/misc_id_mapper.ipynb +++ /dev/null @@ -1,766 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Analyse peptides\n", - "\n", - "## Specification\n", - "- access different levels of peptides easily\n", - "- select training data per gene easily\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "import logging\n", - "logging.basicConfig(level=logging.INFO) # configures root logger\n", - "logger = logging.getLogger()\n", - "logger.info(\"test\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "from config import FN_FASTA_DB, FN_ID_MAP, FN_PEPTIDE_INTENSITIES" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "id_map = pd.read_json(FN_ID_MAP, orient=\"split\")\n", - "\n", - "mask_no_gene = id_map.gene.isna()\n", - "id_map.loc[mask_no_gene, \"gene\"] = \"-\"\n", - "\n", - "\n", - "with open(FN_FASTA_DB) as f:\n", - " data_fasta = json.load(f)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_peptides = pd.read_pickle(FN_PEPTIDE_INTENSITIES)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "set_peptides = set(data_peptides.columns)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- switch between list of proteins with any support and non\n", - " - set threshold of number of peptides per protein over all samples (some peptides uniquely matched to one protein in on sample is just noise -> check razor peptides)\n", - "- show support" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from collections import defaultdict\n", - "import ipywidgets as w\n", - "from config import KEY_FASTA_HEADER, KEY_FASTA_SEQ, KEY_PEPTIDES, KEY_GENE_NAME, KEY_GENE_NAME_FASTA\n", - "\n", - "TGREEN = \"\\033[32m\" # Green Text\n", - "RESET = \"\\033[0;0m\"\n", - "\n", - "w_first_letter = w.Dropdown(\n", - " options=id_map[KEY_GENE_NAME_FASTA].str[0].unique())\n", - "w_genes = w.Dropdown(\n", - " options=id_map.gene.loc[id_map[KEY_GENE_NAME_FASTA].str[0] == w_first_letter.value].unique(),\n", - " value='ACTB'\n", - ")\n", - "\n", - "mask = id_map.gene == w_genes.value\n", - "selected = id_map.loc[mask, \"protein\"]\n", - "\n", - "\n", - "w_proteins_ids = w.Dropdown(options=selected.index)\n", - "w_protein = w.Dropdown(options=selected.unique())\n", - "\n", - "\n", - "def update_gene_list(first_letter):\n", - " \"\"\"Update proteins when new gene is selected\"\"\"\n", - " mask_selected_genes = id_map[KEY_GENE_NAME_FASTA].str[0] == w_first_letter.value\n", - " w_genes.options = id_map.gene.loc[mask_selected_genes].unique()\n", - "\n", - "\n", - "_ = w.interactive_output(update_gene_list, {\"first_letter\": w_first_letter})\n", - "\n", - "\n", - "def update_protein_list(gene):\n", - " mask = id_map[KEY_GENE_NAME_FASTA] == gene\n", - " selected = id_map.loc[mask, \"protein\"]\n", - " w_protein.options = selected.unique()\n", - "# w_proteins_ids.options = selected.loc[selected == w_protein.value].index\n", - "\n", - "\n", - "_ = w.interactive_output(update_protein_list, {\"gene\": w_genes})\n", - " \n", - "\n", - "def update_protein_id_list(protein):\n", - " \"\"\"Update isotope list when protein is selected\"\"\"\n", - " mask = id_map.protein == w_protein.value\n", - " selected = id_map.protein.loc[mask]\n", - " w_proteins_ids.options = selected.index\n", - "\n", - "_ = w.interactive_output(update_protein_id_list, {'protein': w_protein})\n", - "\n", - "d_peptides_observed_prot_id = defaultdict(list)\n", - "\n", - "def show_sequences(prot_id):\n", - " _data = data_fasta[prot_id]\n", - " print(f\"Protein_ID on Uniport: {prot_id}\")\n", - " print(f\"HEADER: {_data[KEY_FASTA_HEADER]}\")\n", - "# print(f\"Seq : {_data[KEY_FASTA_SEQ]}\")\n", - " annotate_seq = \"Peptides: \"\n", - " global d_peptides_observed_prot_id\n", - " for i, _l in enumerate(_data[KEY_PEPTIDES]):\n", - " annotate_seq += f\"\\nNo. of missed K or R: {i}\"\n", - " prot_seq_annotated = _data[KEY_FASTA_SEQ]\n", - " for j, _pep in enumerate(_l):\n", - " if _pep in set_peptides:\n", - " d_peptides_observed_prot_id[prot_id].append(_pep)\n", - " _pep_in_green = TGREEN + f\"{_pep}\" + RESET\n", - " prot_seq_annotated = prot_seq_annotated.replace(_pep, _pep_in_green)\n", - " _pep = _pep_in_green\n", - " if j==0:\n", - " annotate_seq += \"\\n\\t\" + _pep\n", - " else:\n", - " annotate_seq += \",\\n\\t\" + _pep\n", - " print(f\"Seq {i}: {prot_seq_annotated}\")\n", - " print(annotate_seq)\n", - " \n", - " \n", - " display(data_peptides[d_peptides_observed_prot_id[prot_id]].dropna(how='all'))\n", - "\n", - "w_out = w.interactive_output(show_sequences, {\"prot_id\": w_proteins_ids})\n", - "\n", - "label_first_letter = w.Label(value='First letter of Gene')\n", - "label_genes = w.Label('Gene')\n", - "label_protein = w.Label('Protein')\n", - "label_proteins_ids = w.Label('Protein Isotopes')\n", - "\n", - "panel_levels = w.VBox([\n", - " w.HBox([\n", - " w.VBox([label_first_letter, w_first_letter]),\n", - " w.VBox([label_genes, w_genes]),\n", - " w.VBox([label_protein, w_protein]),\n", - " w.VBox([label_proteins_ids, w_proteins_ids])\n", - " ]),\n", - " w_out]\n", - ")\n", - "panel_levels" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- relatively short peptides resulting from one missed cleaveage, do not appear in the upper part." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- `gene` `->` `Protein_ID` (contains information of `gene` `->` `protein_isotopes`\n", - "- `protein_ID` `->` `sequences` (`FN_FASTA_DB`)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pickle\n", - "from tqdm.notebook import tqdm\n", - "from config import FN_PROTEIN_SUPPORT_MAP, FN_PROTEIN_SUPPORT_FREQ\n", - "try:\n", - " df_protein_support = pd.read_pickle(FN_PROTEIN_SUPPORT_MAP)\n", - " with open(FN_PROTEIN_SUPPORT_FREQ, 'rb') as f:\n", - " d_protein_support_freq = pickle.load(f)\n", - "except FileNotFoundError:\n", - " from vaep.utils import sample_iterable\n", - " d_protein_support = {}\n", - " d_protein_support_freq = {}\n", - " for prot_id in tqdm(data_fasta.keys()):\n", - " _data = data_fasta[prot_id]\n", - " peptides_measured = []\n", - " for i, _l in enumerate(_data[KEY_PEPTIDES]):\n", - " for _pep in _l:\n", - " if _pep in set_peptides:\n", - " peptides_measured.append(_pep)\n", - " _d_protein_support = {}\n", - " _df_support_protein = data_peptides[peptides_measured].dropna(how='all')\n", - "\n", - " _n_samples = len(_df_support_protein)\n", - " if _n_samples > 0:\n", - " _d_protein_support['N_samples'] = _n_samples\n", - " d_protein_support_freq[prot_id] = _df_support_protein.notna().sum().to_dict()\n", - " d_protein_support[prot_id] = _d_protein_support\n", - " else:\n", - " d_protein_support[prot_id] = None\n", - " \n", - " df_protein_support = pd.DataFrame(d_protein_support).T.dropna()\n", - " df_protein_support = df_protein_support.join(id_map)\n", - " df_protein_support.to_pickle(FN_PROTEIN_SUPPORT_MAP)\n", - " \n", - " with open(FN_PROTEIN_SUPPORT_FREQ, 'wb') as f:\n", - " pickle.dump(d_protein_support_freq, f)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "l_proteins_good_support = df_protein_support.sort_values(by='N_samples').tail(100).index.to_list()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "d_protein_support_freq['I3L3I0']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Connect to experimental peptide data\n", - "\n", - "Check if counts by `data_fasta`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from tqdm.notebook import tqdm\n", - "\n", - "counts_observed_by_missed_cleavages = {}\n", - "for _protein_id, _data in tqdm(data_fasta.items()):\n", - " _peptides = _data[KEY_PEPTIDES]\n", - " _counts = {}\n", - " for i, _l in enumerate(_peptides):\n", - " _counts[i] = 0\n", - " for _pep in _l:\n", - " if _pep in set_peptides:\n", - " _counts[i] += 1\n", - " counts_observed_by_missed_cleavages[_protein_id] = _counts" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_counts_observed_by_missed_cleavages = pd.DataFrame(\n", - " counts_observed_by_missed_cleavages\n", - ").T" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "from matplotlib import table\n", - "\n", - "fig, axes = plt.subplots(ncols=2, gridspec_kw={\"width_ratios\": [5, 1], \"wspace\": 0.2}, figsize=(10,4))\n", - "\n", - "_counts_summed = df_counts_observed_by_missed_cleavages.sum()\n", - "_counts_summed.name = \"frequency\"\n", - "\n", - "ax = axes[0]\n", - "_ = _counts_summed.plot(kind=\"bar\", ax=ax)\n", - "ax.set_xlabel(\"peptides from n miscleavages\")\n", - "ax.set_ylabel(\"frequency\")\n", - "\n", - "ax = axes[1]\n", - "ax.axis(\"off\")\n", - "_ = pd.plotting.table(ax=ax, data=_counts_summed, loc=\"best\", colWidths=[1], edges='open')\n", - "_ = fig.suptitle('Peptides frequencies')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "These are unnormalized counts in the meaning of that _razor_ peptides are counted as often as they are matched." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = df_counts_observed_by_missed_cleavages != 0\n", - "df_prot_observed = df_counts_observed_by_missed_cleavages.replace(0, pd.NA)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_prot_observed = df_prot_observed.dropna(axis=0, how=\"all\")\n", - "df_prot_observed = df_prot_observed.fillna(0)\n", - "df_prot_observed = df_prot_observed.convert_dtypes()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from vaep.pandas import combine_value_counts\n", - "\n", - "combine_value_counts(df_prot_observed)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "freq_pep_mapped_to_protID = df_prot_observed.sum(axis=1).value_counts()\n", - "freq_pep_mapped_to_protID = freq_pep_mapped_to_protID.sort_index()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "freq_pep_mapped_to_protID" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Genes with support in data\n", - "\n", - "try software to identify the _most likely_ protein. OpenMS or russian alternative? " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Imputation: Train model\n", - "\n", - "> Select Gene or Protein\n", - "\n", - "As the samples are all obtained from the same biological sample (in principal), the single run should somehow be comparable.\n", - "An description of variablity (from the Data Scientist perspective) can highlight some commenly known facts about proteomics experiments:\n", - " - batch effects: Measurements on consecutive days are have to be normalized to each other\n", - " - scoring: PSM are assigned to a peptide based on a score. Small variations can lead to different assignments\n", - " \n", - "Can a complex representation of a sample level out experimental variation on an in principle comparable data. \n", - "\n", - "### Strategy\n", - "- first start using peptides from single Protein_IDs\n", - "- then move to all models from genes\n", - "- explore structure" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import torch" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "d_peptides_observed_prot_id" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "w_select_proteins_good_support = w.Dropdown(options=l_proteins_good_support)\n", - "w_select_proteins_queried = w.Dropdown(options=list(d_peptides_observed_prot_id.keys()))\n", - "w.HBox(\n", - " [\n", - " w.VBox(\n", - " [\n", - " w.Label(f\"Top {len(l_proteins_good_support)} covered proteins\"),\n", - " w_select_proteins_good_support,\n", - " ]\n", - " ),\n", - " w.VBox([w.Label(\"Queried proteins from above\"), w_select_proteins_queried]),\n", - " ]\n", - ")\n", - "# select from top100 or above selection" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Idea: Select a protein which leads to training. Each selection will create a dump of the selected data, which can be used in the `XZY.ipynb` for model fine-tuning." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prot_id = w_select_proteins_good_support.value\n", - "id_map.loc[prot_id]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prot_id = 'P00338' # 'I3L3I0' # w_select_proteins_queried.value # \n", - "_protein, _gene, _ = id_map.loc[prot_id]\n", - "# _gene_fasta" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "w_first_letter.value = _gene[0]\n", - "w_genes.value = _gene\n", - "w_protein.value = _protein\n", - "w_proteins_ids.value = prot_id" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptides_measured = d_peptides_observed_prot_id[prot_id]\n", - "n_peptides_in_selection = len(peptides_measured)\n", - "print(f\"Selected a total of {n_peptides_in_selection} peptides.\") " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_peptides[peptides_measured].notna().sum(axis=1).value_counts().sort_index()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "PROP_DATA_COMPLETENESS = 0.75\n", - "mask_samples_selected = data_peptides[peptides_measured].notna().sum(axis=1) >= int(n_peptides_in_selection * 0.75)\n", - "print(f\"Using a share of at least {PROP_DATA_COMPLETENESS}, i.e. at least {int(n_peptides_in_selection * 0.75)} out of {n_peptides_in_selection}.\",\n", - " f\"In total {mask_samples_selected.sum()} samples.\", sep=\"\\n\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from config import PROTEIN_DUMPS\n", - "_ = data_peptides.loc[mask_samples_selected, peptides_measured]\n", - "_.to_json(PROTEIN_DUMPS / f\"{prot_id}.pkl\")\n", - "_" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import vaep\n", - "from vaep.transform import log\n", - "\n", - "peptides_selected_log10 = data_peptides.loc[mask_samples_selected, peptides_measured].apply(log) # selected in widget overview above\n", - "peptides_selected_log10" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "> The data to be seen here should be **assigned** peptides. Razor peptides are for now not put to one or the other protein (focus only on unique peptides?)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Hyperparameters" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "n_samples, n_features = peptides_selected_log10.shape" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from vaep.models.cmd import parser\n", - "\n", - "BATCH_SIZE = 16\n", - "EPOCHS = 600\n", - "args = ['--batch-size', str(BATCH_SIZE), '--seed', '43', '--epochs', str(EPOCHS), '--log-interval', str(BATCH_SIZE)]\n", - "args = parser.parse_args(args)\n", - "args.cuda = not args.no_cuda and torch.cuda.is_available()\n", - "args" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "torch.manual_seed(args.seed)\n", - "device = torch.device(\"cuda\" if args.cuda else \"cpu\")\n", - "device = torch.device(\"cpu\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "torch.device?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Dataset and DataLoader\n", - "\n", - "The `torch.utils.data.Dataset` can load data into memory, or just create a mapping to data somewhere to be continously loaded by the `torch.utils.data.DataLoader`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptide_intensities = peptides_selected_log10\n", - "detection_limit = float(int(peptide_intensities.min().min()))\n", - "detection_limit " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# from vaep.model import PeptideDatasetInMemory\n", - "\n", - "from torch.utils.data import Dataset\n", - "class PeptideDatasetInMemory(Dataset):\n", - " \"\"\"Peptide Dataset fully in memory.\"\"\"\n", - "\n", - " def __init__(self, data: pd.DataFrame, fill_na=0):\n", - " self.mask_obs = torch.from_numpy(data.notna().values)\n", - " data = data.fillna(fill_na)\n", - " self.peptides = torch.from_numpy(data.values)\n", - " self.length_ = len(data)\n", - "\n", - " def __len__(self):\n", - " return self.length_\n", - "\n", - " def __getitem__(self, idx):\n", - " return self.peptides[idx], self.mask_obs[idx]\n", - "\n", - "\n", - "dataset_in_memory = PeptideDatasetInMemory(peptide_intensities.copy(), detection_limit)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "kwargs = {'num_workers': 1, 'pin_memory': True} if device=='cuda' else {}\n", - "train_loader = torch.utils.data.DataLoader(\n", - " dataset=dataset_in_memory,\n", - " batch_size=args.batch_size, shuffle=True, **kwargs)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for i, (data, mask) in enumerate(train_loader):\n", - " print(\"Nummber of samples in mini-batch: {}\".format(len(data)),\n", - " \"\\tObject-Type: {}\".format(type(mask)))\n", - "# print(data)\n", - "# print(mask)\n", - " break" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data[~mask] = 0\n", - "plt.imshow(data)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "create logged information for tensorboard, see tutorial and docs." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from datetime import datetime\n", - "from torch.utils.tensorboard import SummaryWriter\n", - "writer = SummaryWriter(f'runs/{prot_id}_{format(datetime.now(), \"%y%m%d_%H%M\")}')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "writer.add_image(f'{len(data)} samples heatmap', data, dataformats='HW')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# import importlib; importlib.reload(vaep.model)\n", - "from IPython.core.debugger import set_trace\n", - "\n", - "from torch import optim\n", - "from vaep.models.ae import VAE\n", - "from vaep.models.ae import loss_function\n", - "\n", - "model = VAE(n_features=n_features, n_neurons=30).double().to(device)\n", - "writer.add_graph(model, input_to_model=data)\n", - "\n", - "optimizer = optim.Adam(model.parameters(), lr=1e-4)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13 (default, Mar 28 2022, 06:59:08) [MSC v.1916 64 bit (AMD64)]" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/misc_id_mapper.py b/project/misc_id_mapper.py deleted file mode 100644 index 944d938bc..000000000 --- a/project/misc_id_mapper.py +++ /dev/null @@ -1,458 +0,0 @@ -# --- -# jupyter: -# jupytext: -# text_representation: -# extension: .py -# format_name: percent -# format_version: '1.3' -# jupytext_version: 1.15.0 -# kernelspec: -# display_name: vaep -# language: python -# name: vaep -# --- - -# %% [markdown] -# # Analyse peptides -# -# ## Specification -# - access different levels of peptides easily -# - select training data per gene easily -# - -# %% -import json -import logging -logging.basicConfig(level=logging.INFO) # configures root logger -logger = logging.getLogger() -logger.info("test") - -# %% -import pandas as pd -from config import FN_FASTA_DB, FN_ID_MAP, FN_PEPTIDE_INTENSITIES - -# %% -id_map = pd.read_json(FN_ID_MAP, orient="split") - -mask_no_gene = id_map.gene.isna() -id_map.loc[mask_no_gene, "gene"] = "-" - - -with open(FN_FASTA_DB) as f: - data_fasta = json.load(f) - -# %% -data_peptides = pd.read_pickle(FN_PEPTIDE_INTENSITIES) - -# %% -set_peptides = set(data_peptides.columns) - -# %% [markdown] -# - switch between list of proteins with any support and non -# - set threshold of number of peptides per protein over all samples (some peptides uniquely matched to one protein in on sample is just noise -> check razor peptides) -# - show support - -# %% -from collections import defaultdict -import ipywidgets as w -from config import KEY_FASTA_HEADER, KEY_FASTA_SEQ, KEY_PEPTIDES, KEY_GENE_NAME, KEY_GENE_NAME_FASTA - -TGREEN = "\033[32m" # Green Text -RESET = "\033[0;0m" - -w_first_letter = w.Dropdown( - options=id_map[KEY_GENE_NAME_FASTA].str[0].unique()) -w_genes = w.Dropdown( - options=id_map.gene.loc[id_map[KEY_GENE_NAME_FASTA].str[0] == w_first_letter.value].unique(), - value='ACTB' -) - -mask = id_map.gene == w_genes.value -selected = id_map.loc[mask, "protein"] - - -w_proteins_ids = w.Dropdown(options=selected.index) -w_protein = w.Dropdown(options=selected.unique()) - - -def update_gene_list(first_letter): - """Update proteins when new gene is selected""" - mask_selected_genes = id_map[KEY_GENE_NAME_FASTA].str[0] == w_first_letter.value - w_genes.options = id_map.gene.loc[mask_selected_genes].unique() - - -_ = w.interactive_output(update_gene_list, {"first_letter": w_first_letter}) - - -def update_protein_list(gene): - mask = id_map[KEY_GENE_NAME_FASTA] == gene - selected = id_map.loc[mask, "protein"] - w_protein.options = selected.unique() -# w_proteins_ids.options = selected.loc[selected == w_protein.value].index - - -_ = w.interactive_output(update_protein_list, {"gene": w_genes}) - - -def update_protein_id_list(protein): - """Update isotope list when protein is selected""" - mask = id_map.protein == w_protein.value - selected = id_map.protein.loc[mask] - w_proteins_ids.options = selected.index - -_ = w.interactive_output(update_protein_id_list, {'protein': w_protein}) - -d_peptides_observed_prot_id = defaultdict(list) - -def show_sequences(prot_id): - _data = data_fasta[prot_id] - print(f"Protein_ID on Uniport: {prot_id}") - print(f"HEADER: {_data[KEY_FASTA_HEADER]}") -# print(f"Seq : {_data[KEY_FASTA_SEQ]}") - annotate_seq = "Peptides: " - global d_peptides_observed_prot_id - for i, _l in enumerate(_data[KEY_PEPTIDES]): - annotate_seq += f"\nNo. of missed K or R: {i}" - prot_seq_annotated = _data[KEY_FASTA_SEQ] - for j, _pep in enumerate(_l): - if _pep in set_peptides: - d_peptides_observed_prot_id[prot_id].append(_pep) - _pep_in_green = TGREEN + f"{_pep}" + RESET - prot_seq_annotated = prot_seq_annotated.replace(_pep, _pep_in_green) - _pep = _pep_in_green - if j==0: - annotate_seq += "\n\t" + _pep - else: - annotate_seq += ",\n\t" + _pep - print(f"Seq {i}: {prot_seq_annotated}") - print(annotate_seq) - - - display(data_peptides[d_peptides_observed_prot_id[prot_id]].dropna(how='all')) - -w_out = w.interactive_output(show_sequences, {"prot_id": w_proteins_ids}) - -label_first_letter = w.Label(value='First letter of Gene') -label_genes = w.Label('Gene') -label_protein = w.Label('Protein') -label_proteins_ids = w.Label('Protein Isotopes') - -panel_levels = w.VBox([ - w.HBox([ - w.VBox([label_first_letter, w_first_letter]), - w.VBox([label_genes, w_genes]), - w.VBox([label_protein, w_protein]), - w.VBox([label_proteins_ids, w_proteins_ids]) - ]), - w_out] -) -panel_levels - -# %% [markdown] -# - relatively short peptides resulting from one missed cleaveage, do not appear in the upper part. - -# %% [markdown] -# - `gene` `->` `Protein_ID` (contains information of `gene` `->` `protein_isotopes` -# - `protein_ID` `->` `sequences` (`FN_FASTA_DB`) - -# %% -import pickle -from tqdm.notebook import tqdm -from config import FN_PROTEIN_SUPPORT_MAP, FN_PROTEIN_SUPPORT_FREQ -try: - df_protein_support = pd.read_pickle(FN_PROTEIN_SUPPORT_MAP) - with open(FN_PROTEIN_SUPPORT_FREQ, 'rb') as f: - d_protein_support_freq = pickle.load(f) -except FileNotFoundError: - from vaep.utils import sample_iterable - d_protein_support = {} - d_protein_support_freq = {} - for prot_id in tqdm(data_fasta.keys()): - _data = data_fasta[prot_id] - peptides_measured = [] - for i, _l in enumerate(_data[KEY_PEPTIDES]): - for _pep in _l: - if _pep in set_peptides: - peptides_measured.append(_pep) - _d_protein_support = {} - _df_support_protein = data_peptides[peptides_measured].dropna(how='all') - - _n_samples = len(_df_support_protein) - if _n_samples > 0: - _d_protein_support['N_samples'] = _n_samples - d_protein_support_freq[prot_id] = _df_support_protein.notna().sum().to_dict() - d_protein_support[prot_id] = _d_protein_support - else: - d_protein_support[prot_id] = None - - df_protein_support = pd.DataFrame(d_protein_support).T.dropna() - df_protein_support = df_protein_support.join(id_map) - df_protein_support.to_pickle(FN_PROTEIN_SUPPORT_MAP) - - with open(FN_PROTEIN_SUPPORT_FREQ, 'wb') as f: - pickle.dump(d_protein_support_freq, f) - -# %% -l_proteins_good_support = df_protein_support.sort_values(by='N_samples').tail(100).index.to_list() - -# %% -d_protein_support_freq['I3L3I0'] - -# %% [markdown] -# ## Connect to experimental peptide data -# -# Check if counts by `data_fasta`. - -# %% -from tqdm.notebook import tqdm - -counts_observed_by_missed_cleavages = {} -for _protein_id, _data in tqdm(data_fasta.items()): - _peptides = _data[KEY_PEPTIDES] - _counts = {} - for i, _l in enumerate(_peptides): - _counts[i] = 0 - for _pep in _l: - if _pep in set_peptides: - _counts[i] += 1 - counts_observed_by_missed_cleavages[_protein_id] = _counts - -# %% -df_counts_observed_by_missed_cleavages = pd.DataFrame( - counts_observed_by_missed_cleavages -).T - -# %% -import matplotlib.pyplot as plt -from matplotlib import table - -fig, axes = plt.subplots(ncols=2, gridspec_kw={"width_ratios": [5, 1], "wspace": 0.2}, figsize=(10,4)) - -_counts_summed = df_counts_observed_by_missed_cleavages.sum() -_counts_summed.name = "frequency" - -ax = axes[0] -_ = _counts_summed.plot(kind="bar", ax=ax) -ax.set_xlabel("peptides from n miscleavages") -ax.set_ylabel("frequency") - -ax = axes[1] -ax.axis("off") -_ = pd.plotting.table(ax=ax, data=_counts_summed, loc="best", colWidths=[1], edges='open') -_ = fig.suptitle('Peptides frequencies') - -# %% [markdown] -# These are unnormalized counts in the meaning of that _razor_ peptides are counted as often as they are matched. - -# %% -mask = df_counts_observed_by_missed_cleavages != 0 -df_prot_observed = df_counts_observed_by_missed_cleavages.replace(0, pd.NA) - -# %% -df_prot_observed = df_prot_observed.dropna(axis=0, how="all") -df_prot_observed = df_prot_observed.fillna(0) -df_prot_observed = df_prot_observed.convert_dtypes() - -# %% -from vaep.pandas import combine_value_counts - -combine_value_counts(df_prot_observed) - -# %% -freq_pep_mapped_to_protID = df_prot_observed.sum(axis=1).value_counts() -freq_pep_mapped_to_protID = freq_pep_mapped_to_protID.sort_index() - -# %% -freq_pep_mapped_to_protID - -# %% [markdown] -# ### Genes with support in data -# -# try software to identify the _most likely_ protein. OpenMS or russian alternative? - -# %% - -# %% [markdown] -# ## Imputation: Train model -# -# > Select Gene or Protein -# -# As the samples are all obtained from the same biological sample (in principal), the single run should somehow be comparable. -# An description of variablity (from the Data Scientist perspective) can highlight some commenly known facts about proteomics experiments: -# - batch effects: Measurements on consecutive days are have to be normalized to each other -# - scoring: PSM are assigned to a peptide based on a score. Small variations can lead to different assignments -# -# Can a complex representation of a sample level out experimental variation on an in principle comparable data. -# -# ### Strategy -# - first start using peptides from single Protein_IDs -# - then move to all models from genes -# - explore structure - -# %% -import torch - -# %% -d_peptides_observed_prot_id - -# %% -w_select_proteins_good_support = w.Dropdown(options=l_proteins_good_support) -w_select_proteins_queried = w.Dropdown(options=list(d_peptides_observed_prot_id.keys())) -w.HBox( - [ - w.VBox( - [ - w.Label(f"Top {len(l_proteins_good_support)} covered proteins"), - w_select_proteins_good_support, - ] - ), - w.VBox([w.Label("Queried proteins from above"), w_select_proteins_queried]), - ] -) -# select from top100 or above selection - -# %% [markdown] -# Idea: Select a protein which leads to training. Each selection will create a dump of the selected data, which can be used in the `XZY.ipynb` for model fine-tuning. - -# %% -prot_id = w_select_proteins_good_support.value -id_map.loc[prot_id] - -# %% -prot_id = 'P00338' # 'I3L3I0' # w_select_proteins_queried.value # -_protein, _gene, _ = id_map.loc[prot_id] -# _gene_fasta - -# %% -w_first_letter.value = _gene[0] -w_genes.value = _gene -w_protein.value = _protein -w_proteins_ids.value = prot_id - -# %% -peptides_measured = d_peptides_observed_prot_id[prot_id] -n_peptides_in_selection = len(peptides_measured) -print(f"Selected a total of {n_peptides_in_selection} peptides.") - -# %% -data_peptides[peptides_measured].notna().sum(axis=1).value_counts().sort_index() - -# %% -PROP_DATA_COMPLETENESS = 0.75 -mask_samples_selected = data_peptides[peptides_measured].notna().sum(axis=1) >= int(n_peptides_in_selection * 0.75) -print(f"Using a share of at least {PROP_DATA_COMPLETENESS}, i.e. at least {int(n_peptides_in_selection * 0.75)} out of {n_peptides_in_selection}.", - f"In total {mask_samples_selected.sum()} samples.", sep="\n") - -# %% -from config import PROTEIN_DUMPS -_ = data_peptides.loc[mask_samples_selected, peptides_measured] -_.to_json(PROTEIN_DUMPS / f"{prot_id}.pkl") -_ - -# %% -import vaep -from vaep.transform import log - -peptides_selected_log10 = data_peptides.loc[mask_samples_selected, peptides_measured].apply(log) # selected in widget overview above -peptides_selected_log10 - -# %% [markdown] -# > The data to be seen here should be **assigned** peptides. Razor peptides are for now not put to one or the other protein (focus only on unique peptides?). - -# %% [markdown] -# ### Hyperparameters - -# %% -n_samples, n_features = peptides_selected_log10.shape - -# %% -from vaep.models.cmd import parser - -BATCH_SIZE = 16 -EPOCHS = 600 -args = ['--batch-size', str(BATCH_SIZE), '--seed', '43', '--epochs', str(EPOCHS), '--log-interval', str(BATCH_SIZE)] -args = parser.parse_args(args) -args.cuda = not args.no_cuda and torch.cuda.is_available() -args - -# %% -torch.manual_seed(args.seed) -device = torch.device("cuda" if args.cuda else "cpu") -device = torch.device("cpu") - -# %% -# torch.device? - -# %% [markdown] -# ### Dataset and DataLoader -# -# The `torch.utils.data.Dataset` can load data into memory, or just create a mapping to data somewhere to be continously loaded by the `torch.utils.data.DataLoader`. - -# %% -peptide_intensities = peptides_selected_log10 -detection_limit = float(int(peptide_intensities.min().min())) -detection_limit - -# %% -# from vaep.model import PeptideDatasetInMemory - -from torch.utils.data import Dataset -class PeptideDatasetInMemory(Dataset): - """Peptide Dataset fully in memory.""" - - def __init__(self, data: pd.DataFrame, fill_na=0): - self.mask_obs = torch.from_numpy(data.notna().values) - data = data.fillna(fill_na) - self.peptides = torch.from_numpy(data.values) - self.length_ = len(data) - - def __len__(self): - return self.length_ - - def __getitem__(self, idx): - return self.peptides[idx], self.mask_obs[idx] - - -dataset_in_memory = PeptideDatasetInMemory(peptide_intensities.copy(), detection_limit) - -# %% -kwargs = {'num_workers': 1, 'pin_memory': True} if device=='cuda' else {} -train_loader = torch.utils.data.DataLoader( - dataset=dataset_in_memory, - batch_size=args.batch_size, shuffle=True, **kwargs) - -# %% -for i, (data, mask) in enumerate(train_loader): - print("Nummber of samples in mini-batch: {}".format(len(data)), - "\tObject-Type: {}".format(type(mask))) -# print(data) -# print(mask) - break - -# %% -data[~mask] = 0 -plt.imshow(data) - -# %% [markdown] -# create logged information for tensorboard, see tutorial and docs. - -# %% -from datetime import datetime -from torch.utils.tensorboard import SummaryWriter -writer = SummaryWriter(f'runs/{prot_id}_{format(datetime.now(), "%y%m%d_%H%M")}') - -# %% -writer.add_image(f'{len(data)} samples heatmap', data, dataformats='HW') - -# %% -# import importlib; importlib.reload(vaep.model) -from IPython.core.debugger import set_trace - -from torch import optim -from vaep.models.ae import VAE -from vaep.models.ae import loss_function - -model = VAE(n_features=n_features, n_neurons=30).double().to(device) -writer.add_graph(model, input_to_model=data) - -optimizer = optim.Adam(model.parameters(), lr=1e-4) diff --git a/project/misc_illustrations.ipynb b/project/misc_illustrations.ipynb index 3e09a695d..eef8b6065 100644 --- a/project/misc_illustrations.ipynb +++ b/project/misc_illustrations.ipynb @@ -13,19 +13,22 @@ "metadata": {}, "outputs": [], "source": [ + "from pathlib import Path\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", - "import pandas as pd\n", "import scipy.stats" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ - "import config as cfg" + "FIGUREFOLDER = Path('figures')\n", + "FIGUREFOLDER.mkdir(exist_ok=True, parents=True)" ] }, { diff --git a/project/misc_illustrations.py b/project/misc_illustrations.py index e63c68278..4f4690e02 100644 --- a/project/misc_illustrations.py +++ b/project/misc_illustrations.py @@ -16,13 +16,15 @@ # # Figures for Illustration of concepts # %% +from pathlib import Path import matplotlib.pyplot as plt import numpy as np -import pandas as pd import scipy.stats # %% -import config as cfg +FIGUREFOLDER = Path('figures') +FIGUREFOLDER.mkdir(exist_ok=True, parents=True) + # %% plt.rcParams.update({'xtick.labelsize': 'xx-large', diff --git a/project/misc_protein_support.ipynb b/project/misc_protein_support.ipynb deleted file mode 100644 index 846693e82..000000000 --- a/project/misc_protein_support.ipynb +++ /dev/null @@ -1,739 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Analyse peptides\n", - "\n", - "## Specification\n", - "- access different levels of peptides easily\n", - "- select training data per gene easily\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import time\n", - "import json\n", - "import logging\n", - "\n", - "import pandas as pd\n", - "from IPython.core.debugger import set_trace\n", - "\n", - "\n", - "pd.options.display.float_format = '{:,.1f}'.format\n", - "\n", - "from config import erda_dumps\n", - "from config import FN_FASTA_DB, FN_ID_MAP, FN_PEPTIDE_INTENSITIES, FN_PEPTIDE_STUMP, FOLDER_DATA\n", - "\n", - "logging.basicConfig(level=logging.INFO) # configures root logger\n", - "logger = logging.getLogger()\n", - "logger.info(\"test\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "id_map = pd.read_json(FN_ID_MAP, orient=\"split\")\n", - "\n", - "mask_no_gene = id_map.gene.isna()\n", - "id_map.loc[mask_no_gene, \"gene\"] = \"-\"\n", - "\n", - "with open(FN_FASTA_DB) as f:\n", - " data_fasta = json.load(f)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptides_intensities = pd.read_pickle(erda_dumps.FN_PEPTIDES)\n", - "peptides_intensities.shape" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# idx = peptides_intensities.index.levels[0][:1000]\n", - "peptides_intensities.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptides_intensities = peptides_intensities.unstack()\n", - "peptides_intensities.head()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_peptides = peptides_intensities\n", - "set(data_peptides.dtypes)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "set_peptides = set(data_peptides.columns)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- switch between list of proteins with any support and non\n", - " - set threshold of number of peptides per protein over all samples (some peptides uniquely matched to one protein in on sample is just noise -> check razor peptides)\n", - "- show support" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "peptides_2 = ('TTGIVMDSGDGVTHTVPIYEGYALPHAILRLDLAGR',\n", - " 'LDLAGRDLTDYLMK')\n", - "\n", - "peptides_4 = (\"ILTERGYSFTTTAEREIVR\",\n", - " \"GYSFTTTAEREIVRDIK\",\n", - " \"EIVRDIKEK\",\n", - " \"DIKEKLCYVALDFEQEMATAASSSSLEK\")\n", - "peptides_4[:0:-1]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# logger.setLevel(logging.DEBUG)\n", - "COLORS = [\"\\033[32;2m\", \"\\033[32;1m\", \"0;34;47m\"]\n", - "\n", - "\n", - "def annotate_overlap(peptides):\n", - " i = len(peptides)\n", - " if i > 3:\n", - " raise ValueError(\"Two many peptides provided.\")\n", - " logging.debug(f\"First peptide: {peptides[0]} \")\n", - " base_peptide = peptides[0][::-1]\n", - " logging.debug(f\"Reversed pep: {base_peptide}\")\n", - " colored_part = \"\"\n", - " overlaps = []\n", - " logging.debug(peptides[:0:-1])\n", - " for pep in peptides[:0:-1]:\n", - "\n", - " logger.debug(f\"Find overlap for: {pep}\")\n", - " overlap = \"\"\n", - " overlap_in_last_step = False\n", - " for j, amino_acid in enumerate(pep):\n", - " overlap += amino_acid\n", - " if overlap[::-1] != base_peptide[:len(overlap)]:\n", - " overlap_now = False\n", - " else:\n", - " overlap_in_last_step = True\n", - " logger.debug(f\"Found overlap: {overlap}\")\n", - " if overlap_in_last_step and not overlap_now:\n", - " overlaps.append(overlap)\n", - " break\n", - " logger.debug(\n", - " f\"Search remaining peptide: {base_peptide[len(overlap)::]}\")\n", - " base_peptide = base_peptide[len(overlap)::]\n", - " overlaps.append(base_peptide[::-1])\n", - " return overlaps[::-1]\n", - "\n", - "\n", - "assert ''.join(annotate_overlap(peptides_2)\n", - " ) == \"TTGIVMDSGDGVTHTVPIYEGYALPHAILRLDLAGR\"\n", - "# annotate_overlap(peptides_4) # should raise ValueError\n", - "assert ''.join(annotate_overlap(peptides_4[0:3])) == 'ILTERGYSFTTTAEREIVR'\n", - "assert ''.join(annotate_overlap(peptides_4[1:])) == 'GYSFTTTAEREIVRDIK'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pep_0missed = \"GYSFTTTAER\"\n", - "pep_1missed = [\"ILTERGYSFTTTAER\",\n", - " \"GYSFTTTAEREIVR\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from collections import defaultdict\n", - "import ipywidgets as w\n", - "from config import KEY_FASTA_HEADER, KEY_FASTA_SEQ, KEY_PEPTIDES, KEY_GENE_NAME_FASTA\n", - "\n", - "\n", - "pd.options.display.float_format = '{:,.1f}'.format\n", - "\n", - "TGREEN = \"\\033[32;2m\" # Green Text\n", - "TGREEN_2 = \"\\033[32;1m\" # Green Text\n", - "RESET = \"\\033[0;0m\"\n", - "\n", - "w_first_letter = w.Dropdown(\n", - " options=id_map[KEY_GENE_NAME_FASTA].str[0].unique())\n", - "\n", - "w_genes = w.Dropdown(\n", - " options=id_map.gene.loc[id_map[KEY_GENE_NAME_FASTA].str[0]\n", - " == w_first_letter.value].unique(),\n", - " value='ACTB'\n", - ")\n", - "\n", - "mask = id_map.gene == w_genes.value\n", - "selected = id_map.loc[mask, \"protein\"]\n", - "\n", - "\n", - "w_proteins_ids = w.Dropdown(options=selected.index)\n", - "w_protein = w.Dropdown(options=selected.unique())\n", - "\n", - "\n", - "def update_gene_list(first_letter):\n", - " \"\"\"Update proteins when new gene is selected\"\"\"\n", - " mask_selected_genes = id_map[KEY_GENE_NAME_FASTA].str[0] == w_first_letter.value\n", - " w_genes.options = id_map[KEY_GENE_NAME_FASTA].loc[mask_selected_genes].unique(\n", - " )\n", - "\n", - "\n", - "_ = w.interactive_output(update_gene_list, {\"first_letter\": w_first_letter})\n", - "\n", - "\n", - "def update_protein_list(gene):\n", - " mask = id_map[KEY_GENE_NAME_FASTA] == gene\n", - " selected = id_map.loc[mask, \"protein\"]\n", - " w_protein.options = selected.unique()\n", - "# w_proteins_ids.options = selected.loc[selected == w_protein.value].index\n", - "\n", - "\n", - "_ = w.interactive_output(update_protein_list, {\"gene\": w_genes})\n", - "\n", - "\n", - "def update_protein_id_list(protein):\n", - " \"\"\"Update isotope list when protein is selected\"\"\"\n", - " mask = id_map.protein == w_protein.value\n", - " selected = id_map.protein.loc[mask]\n", - " w_proteins_ids.options = selected.index\n", - "\n", - "\n", - "_ = w.interactive_output(update_protein_id_list, {'protein': w_protein})\n", - "\n", - "d_peptides_observed_prot_id = defaultdict(list)\n", - "\n", - "\n", - "def show_sequences(prot_id):\n", - " _data = data_fasta[prot_id]\n", - " print(f\"Protein_ID on Uniport: {prot_id}\")\n", - " print(f\"HEADER: {_data[KEY_FASTA_HEADER]}\")\n", - "# print(f\"Seq : {_data[KEY_FASTA_SEQ]}\")\n", - " annotate_seq = \"Peptides: \"\n", - " global d_peptides_observed_prot_id\n", - " for i, _l in enumerate(_data[KEY_PEPTIDES]):\n", - " annotate_seq += f\"\\nNo. of missed K or R: {i}\"\n", - " prot_seq_annotated = _data[KEY_FASTA_SEQ]\n", - " _change_color = False\n", - " for j, _pep in enumerate(_l):\n", - " if _pep in set_peptides:\n", - " d_peptides_observed_prot_id[prot_id].append(_pep)\n", - " if _change_color is False:\n", - " _pep_in_green = TGREEN + f\"{_pep}\" + RESET\n", - " _change_color = True\n", - " else:\n", - " _pep_in_green = TGREEN_2 + f\"{_pep}\" + RESET\n", - " _change_color = False\n", - " prot_seq_annotated = prot_seq_annotated.replace(\n", - " _pep, _pep_in_green)\n", - " _pep = _pep_in_green\n", - " else:\n", - " _change_color = False\n", - " if j == 0:\n", - " annotate_seq += \"\\n\\t\"\n", - " else:\n", - " annotate_seq += \",\\n\\t\"\n", - " annotate_seq += _pep\n", - "\n", - " print(f\"Seq {i}: {prot_seq_annotated}\")\n", - " print(annotate_seq)\n", - "\n", - " _ = data_peptides[d_peptides_observed_prot_id[prot_id]].dropna(how='all')\n", - " if _.columns.size > 2:\n", - " display(_)\n", - " display(_.describe())\n", - " else:\n", - " print(\"\\nNo empirical evidence for protein\")\n", - "\n", - "\n", - "w_out = w.interactive_output(show_sequences, {\"prot_id\": w_proteins_ids})\n", - "\n", - "label_first_letter = w.Label(value='First letter of Gene')\n", - "label_genes = w.Label('Gene')\n", - "label_protein = w.Label('Protein')\n", - "label_proteins_ids = w.Label('Protein Isotopes')\n", - "\n", - "panel_levels = w.VBox([\n", - " w.HBox([\n", - " w.VBox([label_first_letter, w_first_letter]),\n", - " w.VBox([label_genes, w_genes]),\n", - " w.VBox([label_protein, w_protein]),\n", - " w.VBox([label_proteins_ids, w_proteins_ids])\n", - " ]),\n", - " w_out]\n", - ")\n", - "panel_levels" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "> create styler object?\n", - "\n", - "- [ ] replace zeros with NaN\n", - "- [ ] display summary statistics on log-scale (but do not compute summary based on log-scale)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Get meta-data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "query_template = \"https://www.uniprot.org/uniprot/?query=accession:{prot_id}&format=txt\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- relatively short peptides resulting from one missed cleaveage, do not appear in the upper part." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- `gene` `->` `Protein_ID` (contains information of `gene` `->` `protein_isotopes`\n", - "- `protein_ID` `->` `sequences` (`FN_FASTA_DB`)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pickle\n", - "from tqdm.notebook import tqdm\n", - "from config import FN_PROTEIN_SUPPORT_MAP, FN_PROTEIN_SUPPORT_FREQ\n", - "# from vaep.utils import sample_iterable\n", - "\n", - "try:\n", - " if (time.time() - os.path.getmtime(FN_PROTEIN_SUPPORT_MAP)) / 3600 / 24 > 7:\n", - " # recompute file every week\n", - " raise FileNotFoundError\n", - " df_protein_support = pd.read_pickle(FN_PROTEIN_SUPPORT_MAP)\n", - " with open(FN_PROTEIN_SUPPORT_FREQ, 'rb') as f:\n", - " d_protein_support_freq = pickle.load(f)\n", - "except FileNotFoundError:\n", - " d_protein_support = {}\n", - " d_protein_support_freq = {}\n", - " for prot_id in tqdm(data_fasta.keys()):\n", - " _data = data_fasta[prot_id]\n", - " peptides_measured = []\n", - " for i, _l in enumerate(_data[KEY_PEPTIDES]):\n", - " for _pep in _l:\n", - " if _pep in set_peptides:\n", - " peptides_measured.append(_pep)\n", - " _d_protein_support = {}\n", - " _df_support_protein = data_peptides[peptides_measured].dropna(\n", - " how='all')\n", - "\n", - " _n_samples = len(_df_support_protein)\n", - " if _n_samples > 0:\n", - " _d_protein_support['N_samples'] = _n_samples\n", - " d_protein_support_freq[prot_id] = _df_support_protein.notna(\n", - " ).sum().to_dict()\n", - " d_protein_support[prot_id] = _d_protein_support\n", - " else:\n", - " d_protein_support[prot_id] = None\n", - "\n", - " df_protein_support = pd.DataFrame(d_protein_support).T.dropna()\n", - " df_protein_support = df_protein_support.join(id_map)\n", - " df_protein_support.to_pickle(FN_PROTEIN_SUPPORT_MAP)\n", - "\n", - " with open(FN_PROTEIN_SUPPORT_FREQ, 'wb') as f:\n", - " pickle.dump(d_protein_support_freq, f)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "l_proteins_good_support = df_protein_support.sort_values(\n", - " by='N_samples').tail(100).index.to_list()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "d_protein_support_freq['I3L3I0']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Connect to experimental peptide data\n", - "\n", - "Check if counts by `data_fasta`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from tqdm.notebook import tqdm\n", - "\n", - "counts_observed_by_missed_cleavages = {}\n", - "for _protein_id, _data in tqdm(data_fasta.items()):\n", - " _peptides = _data[KEY_PEPTIDES]\n", - " _counts = {}\n", - " for i, _l in enumerate(_peptides):\n", - " _counts[i] = 0\n", - " for _pep in _l:\n", - " if _pep in set_peptides:\n", - " _counts[i] += 1\n", - " counts_observed_by_missed_cleavages[_protein_id] = _counts" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_counts_observed_by_missed_cleavages = pd.DataFrame(\n", - " counts_observed_by_missed_cleavages\n", - ").T" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "from matplotlib import table\n", - "\n", - "fig, axes = plt.subplots(ncols=2, gridspec_kw={\"width_ratios\": [\n", - " 5, 1], \"wspace\": 0.2}, figsize=(10, 4))\n", - "\n", - "_counts_summed = df_counts_observed_by_missed_cleavages.sum()\n", - "_counts_summed.name = \"frequency\"\n", - "\n", - "ax = axes[0]\n", - "_ = _counts_summed.plot(kind=\"bar\", ax=ax)\n", - "ax.set_xlabel(\"peptides from n miscleavages\")\n", - "ax.set_ylabel(\"frequency\")\n", - "\n", - "ax = axes[1]\n", - "ax.axis(\"off\")\n", - "_ = pd.plotting.table(ax=ax, data=_counts_summed,\n", - " loc=\"best\", colWidths=[1], edges='open')\n", - "_ = fig.suptitle('Peptides frequencies')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "These are unnormalized counts in the meaning of that _razor_ peptides are counted as often as they are matched." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mask = df_counts_observed_by_missed_cleavages != 0\n", - "df_prot_observed = df_counts_observed_by_missed_cleavages.replace(0, pd.NA)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_prot_observed = df_prot_observed.dropna(axis=0, how=\"all\")\n", - "df_prot_observed = df_prot_observed.fillna(0)\n", - "df_prot_observed = df_prot_observed.convert_dtypes()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from vaep.pandas import combine_value_counts\n", - "\n", - "combine_value_counts(df_prot_observed)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "freq_pep_mapped_to_protID = df_prot_observed.sum(axis=1).value_counts()\n", - "freq_pep_mapped_to_protID = freq_pep_mapped_to_protID.sort_index()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "freq_pep_mapped_to_protID" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Genes with support in data\n", - "\n", - "try software to identify the _most likely_ protein. [PyOpenMS](https://pyopenms.readthedocs.io/en/latest/) or [Pyteomics](https://pyteomics.readthedocs.io/en/latest/)? " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Imputation: Train model\n", - "\n", - "> Select Gene or Protein\n", - "\n", - "As the samples are all obtained from the same biological sample (in principal), the single run should somehow be comparable.\n", - "An description of variablity (from the Data Scientist perspective) can highlight some commenly known facts about proteomics experiments:\n", - " - batch effects: Measurements on consecutive days are have to be normalized to each other\n", - " - scoring: PSM are assigned to a peptide based on a score. Small variations can lead to different assignments\n", - " \n", - "Can a complex representation of a sample level out experimental variation on an in principle comparable data. \n", - "\n", - "### Strategy\n", - "- first start using peptides from single Protein_IDs\n", - "- then move to all models from genes\n", - "- explore structure" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "d_peptides_observed_prot_id" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_peptides.shape" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from config import PROTEIN_DUMPS\n", - "from vaep.transform import log\n", - "import vaep\n", - "w_select_proteins_good_support = w.Dropdown(options=l_proteins_good_support)\n", - "w_select_proteins_queried = w.Dropdown(\n", - " options=list(d_peptides_observed_prot_id.keys()))\n", - "\n", - "# select from top100 or above\n", - "\n", - "\n", - "def main_trigger(prot_id):\n", - " \"\"\"Explore protein data\n", - "\n", - " Global Variables used\n", - " ---------------------\n", - " data_peptides : pandas.DataFrame\n", - " id_map : pandas.DataFrame\n", - " d_peptides_observed_prot_id: dict\n", - "\n", - "\n", - " Global variables set\n", - " --------------------\n", - " peptides_selected_log10: pandas.DataFrame\n", - " Current selection of data for protein_id. All possible features are returned. log10 transformed\n", - " prod_id : str\n", - " Passed prot_id to function exposed globally\n", - " \"\"\"\n", - " print(f'Protein Identifier: {prot_id}')\n", - " # Select gene name, based on selected FASTA-File\n", - " _gene_name = id_map.loc[prot_id, KEY_GENE_NAME_FASTA]\n", - " # Protein Name summarized several UNIPROT isotopes (PROT, PROT_2, PROT_3, etc)\n", - " _protein = id_map.protein.loc[prot_id]\n", - " print(f'Gene Identifier {_gene_name}')\n", - " # configure viewer above\n", - " w_first_letter.value = _gene_name[0]\n", - " w_genes.value = _gene_name\n", - " w_protein.value = _protein\n", - " w_proteins_ids.value = prot_id\n", - "\n", - " # get observed peptides according to pre-computed dictionary\n", - " peptides_measured = d_peptides_observed_prot_id[prot_id]\n", - " n_peptides_in_selection = len(peptides_measured)\n", - " print(\n", - " f\"Found {n_peptides_in_selection} peptides measured of this protein.\\n\\n\")\n", - "\n", - " # select subsample (as view) of peptides\n", - " peptides_selected = data_peptides[peptides_measured]\n", - " mask_selected_notna = data_peptides[peptides_measured].notna()\n", - " selected_notna_summed_ax1 = mask_selected_notna.sum(axis=1)\n", - " print(\"How many samples have how many peptides quantified?\")\n", - " for n_peptides, n_samples in selected_notna_summed_ax1.value_counts().sort_index().tail(10).items():\n", - " print(f\"In {n_samples:5} samples are {n_peptides:5} peptides measured.\")\n", - "\n", - " PROP_DATA_COMPLETENESS = 0.5\n", - " mask_samples_selected = selected_notna_summed_ax1 >= int(\n", - " n_peptides_in_selection * PROP_DATA_COMPLETENESS)\n", - " print(f\"\\nUsing a share of at least {PROP_DATA_COMPLETENESS}, \"\n", - " f\"i.e. at least {int(n_peptides_in_selection * PROP_DATA_COMPLETENESS)} out of {n_peptides_in_selection}.\",\n", - " f\"In total {mask_samples_selected.sum()} samples are selected for further analysis.\", sep=\"\\n\")\n", - " # from IPython.core.debugger import set_trace; set_trace()\n", - " _ = peptides_selected.loc[mask_samples_selected, peptides_measured]\n", - " _.index.name = f\"protein_id {prot_id}\"\n", - " # _.to_json(PROTEIN_DUMPS / f\"{prot_id}.json\")\n", - "\n", - " display(_)\n", - " # display(_.describe())\n", - " global peptides_selected_log10\n", - " peptides_selected_log10 = _.apply(log) # selected in widget overview above\n", - " display(peptides_selected_log10)\n", - " display(peptides_selected_log10.describe())\n", - " global prot_last\n", - " prot_last = prot_id\n", - "\n", - "\n", - "w.VBox([\n", - " w.HBox(\n", - " [\n", - " w.VBox(\n", - " [\n", - " w.Label(\n", - " f\"Top {len(l_proteins_good_support)} covered proteins\"),\n", - " w_select_proteins_good_support,\n", - " ]\n", - " ),\n", - " w.VBox([w.Label(\"Queried proteins from above\"),\n", - " w_select_proteins_queried]),\n", - " ]\n", - " ),\n", - " w.interactive_output(\n", - " main_trigger, {\"prot_id\": w_select_proteins_good_support})\n", - "])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Idea: Select a protein which leads to training. Each selection will create a dump of the selected data, which can be used in the `XZY.ipynb` for model fine-tuning. ( A model per protein/gene?)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "vaep", - "language": "python", - "name": "vaep" - }, - "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.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/project/src/file_utils.py b/project/src/file_utils.py deleted file mode 100644 index 20d317f71..000000000 --- a/project/src/file_utils.py +++ /dev/null @@ -1,223 +0,0 @@ -import os -from collections import namedtuple -from pathlib import Path -import logging - -from tqdm import tqdm - -import pandas as pd -from pandas.errors import EmptyDataError - -import xmltodict -from numpy import dtype - -logger = logging.getLogger('src.file_utils.py') - - -MQ_VERSION = '1.6.12.0' - - -def check_for_key(iterable, key): - """Check for key in items of Iterable - using `in`(`__contains__`). - - Parameters - ---------- - iterable : Iterable of Strings - Iterable of items which the key can be checked for - key : String - key to check for using `key in item` of Iterable. - - Returns - ------- - string, int - Returns zero if nothing is found, otherwise a string. - If only one item is found containing the key, return this. - Multiple hits are returned connacotaed using an underscore. - """ - hits = [x for x in iterable if key in x] - n_hits = len(hits) - if n_hits == 1: - return hits[0] - elif n_hits == 0: - return 0 - elif n_hits > 1: - return '_'.join(iterable) - - -# can file-loading be made concurrent? -# check tf.data - - -def load_summary(filepath: str = 'summary.txt') -> pd.DataFrame: - f"""Load MaxQuant {MQ_VERSION} summary.txt file. - - Parameters - ---------- - filepath : str, optional - filepath, by default 'summary.txt' - - Returns - ------- - pd.DataFrame - Text-File is returned as pandas.DataFrame - """ - df = pd.read_table(filepath) - df = df.T - df = df.iloc[:, :-1] - return df - - -def load_mqpar_xml(filepath:Path) -> dict: - f"""Load MaxQuant {MQ_VERSION}parameter file in xml format which stores parameters for MaxQuant run, - including version numbers. - - Parameters - ---------- - filepath : str, optional - filepath to xml- parameter file - - Returns - ------- - dict - XML-File parsed as dictionary - """ - with open(filepath) as f: - _ = f.readline() - xml = f.read() - - return xmltodict.parse(xml) - - -types_peptides = {'N-term cleavage window': dtype('O'), - 'C-term cleavage window': dtype('O'), - 'Amino acid before': dtype('O'), - 'First amino acid': dtype('O'), - 'Second amino acid': dtype('O'), - 'Second last amino acid': dtype('O'), - 'Last amino acid': dtype('O'), - 'Amino acid after': dtype('O'), - 'A Count': dtype('int64'), - 'R Count': dtype('int64'), - 'N Count': dtype('int64'), - 'D Count': dtype('int64'), - 'C Count': dtype('int64'), - 'Q Count': dtype('int64'), - 'E Count': dtype('int64'), - 'G Count': dtype('int64'), - 'H Count': dtype('int64'), - 'I Count': dtype('int64'), - 'L Count': dtype('int64'), - 'K Count': dtype('int64'), - 'M Count': dtype('int64'), - 'F Count': dtype('int64'), - 'P Count': dtype('int64'), - 'S Count': dtype('int64'), - 'T Count': dtype('int64'), - 'W Count': dtype('int64'), - 'Y Count': dtype('int64'), - 'V Count': dtype('int64'), - 'U Count': dtype('int64'), - 'O Count': dtype('int64'), - 'Length': dtype('int64'), - 'Missed cleavages': dtype('int64'), - 'Mass': dtype('float64'), - 'Proteins': dtype('O'), - 'Leading razor protein': dtype('O'), - 'Start position': dtype('float64'), - 'End position': dtype('float64'), - 'Gene names': dtype('O'), - 'Protein names': dtype('O'), - 'Unique (Groups)': dtype('O'), - 'Unique (Proteins)': dtype('O'), - 'Charges': dtype('O'), - 'PEP': dtype('float64'), - 'Score': dtype('float64'), - 'Intensity': dtype('int64'), - 'Reverse': dtype('O'), - 'Potential contaminant': dtype('O'), - 'id': dtype('int64'), - 'Protein group IDs': dtype('O'), - 'Mod. peptide IDs': dtype('O'), - 'Evidence IDs': dtype('O'), - 'MS/MS IDs': dtype('O'), - 'Best MS/MS': dtype('float64'), - 'Oxidation (M) site IDs': dtype('O'), - 'MS/MS Count': dtype('int64')} - - -# def load_peptide_intensities(filepath): -# f"""Load Intensities from `peptides.txt`. -# Data types of columns as of in MaxQuant {MQ_VERSION} - -# Parameters -# ---------- -# filepath : str -# filepath (rel or absolute) to MQ peptides.txt - -# Returns -# ------- -# pandas.DataFrame -# Return text file as DataFrame. -# """ -# df = pd.read_table(filepath, index_col='Sequence', dtype=types_peptides) -# return df[['Intensity']] - - -dtypes_proteins = {'Protein IDs': dtype('O'), - 'Majority protein IDs': dtype('O'), - 'Peptide counts (all)': dtype('O'), - 'Peptide counts (razor+unique)': dtype('O'), - 'Peptide counts (unique)': dtype('O'), - 'Protein names': dtype('O'), - 'Gene names': dtype('O'), - 'Fasta headers': dtype('O'), - 'Number of proteins': dtype('int64'), - 'Peptides': dtype('int64'), - 'Razor + unique peptides': dtype('int64'), - 'Unique peptides': dtype('int64'), - 'Sequence coverage [%]': dtype('float64'), - 'Unique + razor sequence coverage [%]': dtype('float64'), - 'Unique sequence coverage [%]': dtype('float64'), - 'Mol. weight [kDa]': dtype('float64'), - 'Sequence length': dtype('int64'), - 'Sequence lengths': dtype('O'), - 'Q-value': dtype('float64'), - 'Score': dtype('float64'), - 'Intensity': dtype('int64'), - 'MS/MS count': dtype('int64'), - 'Only identified by site': dtype('O'), - 'Reverse': dtype('O'), - 'Potential contaminant': dtype('O'), - 'id': dtype('int64'), - 'Peptide IDs': dtype('O'), - 'Peptide is razor': dtype('O'), - 'Mod. peptide IDs': dtype('O'), - 'Evidence IDs': dtype('O'), - 'MS/MS IDs': dtype('O'), - 'Best MS/MS': dtype('O'), - 'Oxidation (M) site IDs': dtype('O'), - 'Oxidation (M) site positions': dtype('O'), - 'Taxonomy IDs': dtype('O')} - - -def load_protein_intensities(filepath): - f"""Load Intensities from `proteins.txt`. - Data types of columns as of in MaxQuant {MQ_VERSION} - - Parameters - ---------- - filepath : str - filepath (rel or absolute) to MQ proteins.txt - - Returns - ------- - pandas.DataFrame - Return text file as DataFrame. - """ - df = pd.read_table( - filepath, index_col='Majority protein IDs', dtype=dtypes_proteins) - return df[['Intensity']] - - - diff --git a/project/src/setup_logging.py b/project/src/setup_logging.py deleted file mode 100644 index 4eb0f3e2a..000000000 --- a/project/src/setup_logging.py +++ /dev/null @@ -1,9 +0,0 @@ -from .logging import * - -logger = logging.getLogger() # returns root-logger -logger.setLevel(logging.CRITICAL) # silence for everything else -logger.handlers = [] - - -logger = setup_logger(logger=logging.getLogger('vaep')) -logger.info("'vaep' logger setup completed.") \ No newline at end of file diff --git a/vaep/analyzers/analyzers.py b/vaep/analyzers/analyzers.py index 7dbd95917..364dbfef4 100644 --- a/vaep/analyzers/analyzers.py +++ b/vaep/analyzers/analyzers.py @@ -2,6 +2,8 @@ from pathlib import Path from types import SimpleNamespace from typing import Tuple, Union, List + +import logging import random @@ -21,8 +23,8 @@ from vaep.pandas import _add_indices from vaep.io.datasplits import long_format, wide_format -from . import metadata +logger = logging.getLogger(__name__) __doc__ = 'A collection of Analyzers to perform certain type of analysis.' @@ -243,18 +245,6 @@ def get_prop_not_na(self): """Get prop. of not NA values for each sample.""" return self.df.notna().sum(axis=1) / self.df.shape[-1] - def add_metadata(self, add_prop_not_na=True): - d_meta = metadata.get_metadata_from_filenames(self.df.index) - self.df_meta = pd.DataFrame.from_dict( - d_meta, orient='index') - self.df_meta.index.name = self.df.index.name - print(f'Created metadata DataFrame attribute `df_meta`.') - # add proportion on not NA to meta data - if add_prop_not_na: - self.df_meta['prop_not_na'] = self.get_prop_not_na() - print(f'Added proportion of not NA values based on `df` intensities.') - return self.df_meta - def get_PCA(self, n_components=2, imputer=SimpleImputer): self.imputer_ = imputer() X = self.imputer_.fit_transform(self.df) @@ -263,11 +253,14 @@ def get_PCA(self, n_components=2, imputer=SimpleImputer): PCs, self.pca_ = run_pca(X, n_components=n_components) if not hasattr(self, 'df_meta'): - _ = self.add_metadata() + logger.warning('No metadata available, please set "df_meta" first.') try: PCs['ms_instrument'] = self.df_meta['ms_instrument'].astype('category') except KeyError: - print("No MS instrument added.") + logger.warning("No MS instrument added.") + except AttributeError: + logger.warning("No metadata available, please set 'df_meta' first.") + logger.warning("No MS instrument added.") return PCs def calculate_PCs(self, new_df, is_wide=True): @@ -289,7 +282,7 @@ def plot_pca(self,): self.is_wide_format = True if not hasattr(self, 'df_meta'): - _ = self.add_metadata() + raise AttributeError('No metadata available, please set "df_meta" first.') PCs = self.get_PCA() cols = list(PCs.columns) @@ -416,26 +409,6 @@ def _plot(self, fct, meta_key: str, save: bool = True): # def read_csv(fname:str, nrows:int, index_col:str=None)-> pd.DataFrame: # return pd.read_csv(fname, index_col=index_col, low_memory=False, nrows=nrows) -def build_metadata_df(filenames: pd.Index) -> pd.DataFrame: - """Build a DataFrame based on a list of strings (an Index) to parse. - Is strongly coupled to the analysis context. - - Parameters - ---------- - filenames : pd.Index - An Iterable with strings. - - Returns - ------- - pd.DataFrame - A DataFrame with the parsed metadata. - """ - - d_meta = metadata.get_metadata_from_filenames(filenames) - df_meta = pd.DataFrame.from_dict(d_meta, orient='index') - df_meta.index.name = filenames.name - return df_meta - def get_consecutive_data_indices(df, n_samples): index = df.sort_index().index diff --git a/vaep/analyzers/metadata.py b/vaep/analyzers/metadata.py deleted file mode 100644 index 4e843093d..000000000 --- a/vaep/analyzers/metadata.py +++ /dev/null @@ -1,179 +0,0 @@ -from typing import Iterable -import re -import logging - -logger = logging.getLogger('vaep') - -# from collections import namedtuple -# columns = 'date ms_instrument lc_instrument researcher rest'.split() -# RunMetaData = namedtuple('RunMetaData', columns) - -#Vyt, ss, pcp, lvs, teph -regex_researcher = '[_]*[A-Z]*[a-z]*[-]*[A-Z]*[a-zA-Z]*[_]*' - -assert re.search(regex_researcher, 'HeWe_').group() == 'HeWe_' -assert re.search(regex_researcher, '_HeWe_').group() == '_HeWe_' -assert re.search(regex_researcher, 'HeWE_').group() == 'HeWE_' -assert re.search(regex_researcher, '_HeWE_').group() == '_HeWE_' - -regex_lc_instrument = '[_]*([nN]|(UP|up))*((lc)|(LC)|(CL)|([eE][vV][oO]))[a-zA-Z0-9]*[_]*' - -assert re.search(regex_lc_instrument, '_nlc1_').group() == '_nlc1_' -assert re.search(regex_lc_instrument, '_LC6_').group() == '_LC6_' -assert re.search(regex_lc_instrument, '_nLC6_').group() == '_nLC6_' -assert re.search(regex_lc_instrument, 'nLC02_').group() == 'nLC02_' -assert re.search(regex_lc_instrument, '_UPCL_').group() == '_UPCL_' -assert re.search(regex_lc_instrument, '_Evo_').group() == '_Evo_' -assert re.search(regex_lc_instrument, '_EvO_').group() == '_EvO_' - - -# check not HeLa, HeLA, ON, OFF MNT, MA, QC, ALL -regex_not_researcher = '[Hh][eE][Ll][aA]|ON|OFF|MNT|MA|QC|ALL|method|Test' - -assert re.search(regex_not_researcher, 'HeLa').group() == 'HeLa' -assert re.search(regex_not_researcher, 'Hela').group() == 'Hela' -assert re.search(regex_not_researcher, 'hela').group() == 'hela' -assert re.search(regex_not_researcher, 'MNT').group() == 'MNT' -assert re.search(regex_not_researcher, 'MA').group() == 'MA' -assert re.search(regex_not_researcher, 'QC').group() == 'QC' -assert re.search(regex_not_researcher, 'MA_OFF').group() == 'MA' -assert re.search(regex_not_researcher, '_LiNi_') is None - - -type_run = {'MA': 'MNT', - 'MNT': 'MNT', - 'QC': 'QC'} - -# based on hints from core facility -ms_instrument_mapping = { - 'LUMOS1': 'LUMOS', - 'ECPL0': 'EXPL0', - 'Q10': 'QE10' - -} - -lc_instrument_mapping = { - f'LC{i}': f'LC{i:02}' for i in range(10) -} - - -def get_metadata_from_filenames(selected: Iterable, apply_cleaning=False): - data_meta = {} - for filename in selected: - # The first two fields are in order, the rest needs matching. - _entry = {} - try: - _entry['date'], _entry['ms_instrument'], _rest_filename = filename.split( - '_', maxsplit=2) - except ValueError: - logger.error(f'Unexpected filenaming format: {filename}') - _entry['rest'] = filename - data_meta[filename] = _entry - continue - - _entry['ms_instrument'] = _entry['ms_instrument'].upper() - if apply_cleaning and _entry['ms_instrument'] in ms_instrument_mapping: - _entry['ms_instrument'] = ms_instrument_mapping[_entry['ms_instrument']] - - _entry['lc_instrument'] = None - try: - for regex in [regex_lc_instrument, '[_]*[Bb][Rr][0-9]+[_]*']: - try: - _entry['lc_instrument'] = re.search( - regex, _rest_filename).group().strip('_') - break - except AttributeError: - pass - finally: - if _entry['lc_instrument']: - _rest_filename = _rest_filename.replace( - _entry['lc_instrument'], '').replace('__', '_') - _entry['lc_instrument'] = _entry['lc_instrument'].upper() - if _entry['lc_instrument'][0] == 'N': - if apply_cleaning: - _entry['lc_instrument'] = f"{_entry['lc_instrument'][1:]}" - else: - _entry['lc_instrument'] = f"n{_entry['lc_instrument'][1:]}" - if apply_cleaning and _entry['lc_instrument'] in lc_instrument_mapping: - _entry['lc_instrument'] = lc_instrument_mapping[_entry['lc_instrument']] - else: - # try rare cases: "20191216_QE4_nL4_MM_QC_MNT_HELA_01 - lc_rare_cases = { - 'nL4': 'nLC4', - 'nL0': 'nLC0', - 'nL2': 'nLC2', - } - for typo_key, replacement_key in lc_rare_cases.items(): - if typo_key in _rest_filename: - _entry['lc_instrument'] = replacement_key - _rest_filename = _rest_filename.replace( - f'{typo_key}_', '') - if not _entry['lc_instrument']: - logger.error(f'Could not find LC instrument in {filename}') - # researcher after LC instrument - try: - _entry['researcher'] = re.search( - regex_researcher, _rest_filename).group().strip('_') - _cleaned_filename = _rest_filename.replace( - _entry['researcher'], '').replace('__', '_') - while re.search(regex_not_researcher, _entry['researcher']): - _entry['researcher'] = re.search( - regex_researcher, _cleaned_filename) - if _entry['researcher']: - _entry['researcher'] = _entry['researcher'].group().strip('_') - else: - raise AttributeError - _cleaned_filename = _cleaned_filename.replace( - _entry['researcher'], '').replace('__', '_') - if _entry['researcher']: - _rest_filename = _rest_filename.replace( - _entry['researcher'], '').replace('__', '_') - else: - _entry['researcher'] = None - except AttributeError: - logger.critical(f'Found no researcher ID: {filename}') - _entry['researcher'] = None - - _entry['rest'] = _rest_filename - data_meta[filename] = _entry - return data_meta - - -test_cases = ['20131014_QE5_UPLC9_ALL_MNT_HELA_01', - '20150830_qe3_uplc9_LVS_MNT_HELA_07', - '20191216_QE4_nL4_MM_QC_MNT_HELA_01_20191217122319', - '20191012_QE1_nL0_GP_SA_HELA_L-CTR_M-VLX+THL_H-VLX+THL+MLN_GGIP_EXP4_F01', - '20181027_QE8_nL2_QC_AGF_MNT_BSA_01' - ] -# 20150622_QE5_UPLC8_ALL_QC_Hela_method_Test - -# print(get_metadata_from_filenames(test_cases)) - -assert get_metadata_from_filenames(test_cases) == { - '20131014_QE5_UPLC9_ALL_MNT_HELA_01': {'date': '20131014', - 'ms_instrument': 'QE5', - 'lc_instrument': 'UPLC9', - 'researcher': None, - 'rest': '_ALL_MNT_HELA_01'}, - '20150830_qe3_uplc9_LVS_MNT_HELA_07': {'date': '20150830', - 'ms_instrument': 'QE3', - 'lc_instrument': 'UPLC9', - 'researcher': 'LVS', - 'rest': '_MNT_HELA_07'}, - '20191216_QE4_nL4_MM_QC_MNT_HELA_01_20191217122319': {'date': '20191216', - 'ms_instrument': 'QE4', - 'lc_instrument': 'nLC4', - 'researcher': 'MM', - 'rest': '_QC_MNT_HELA_01_20191217122319'}, - '20191012_QE1_nL0_GP_SA_HELA_L-CTR_M-VLX+THL_H-VLX+THL+MLN_GGIP_EXP4_F01': - {'date': '20191012', - 'ms_instrument': 'QE1', - 'lc_instrument': 'nLC0', - 'researcher': 'GP', - 'rest': '_SA_HELA_L-CTR_M-VLX+THL_H-VLX+THL+MLN_GGIP_EXP4_F01'}, - '20181027_QE8_nL2_QC_AGF_MNT_BSA_01': {'date': '20181027', - 'ms_instrument': 'QE8', - 'lc_instrument': 'nLC2', - 'researcher': 'AGF', - 'rest': 'QC_MNT_BSA_01'}, -} diff --git a/vaep/databases/__init__.py b/vaep/databases/__init__.py index e28e2c7c8..e69de29bb 100644 --- a/vaep/databases/__init__.py +++ b/vaep/databases/__init__.py @@ -1 +0,0 @@ -from . import uniprot diff --git a/vaep/databases/uniprot.py b/vaep/databases/uniprot.py deleted file mode 100644 index 65c03270b..000000000 --- a/vaep/databases/uniprot.py +++ /dev/null @@ -1,214 +0,0 @@ -""" -New UniProt REST API, see -https://www.uniprot.org/help/id_mapping. -""" -import re -import time -import json -import zlib -from xml.etree import ElementTree -from urllib.parse import urlparse, parse_qs, urlencode -import requests -from requests.adapters import HTTPAdapter, Retry - - -POLLING_INTERVAL = 3 -API_URL = "https://rest.uniprot.org" - - -retries = Retry(total=5, backoff_factor=0.25, status_forcelist=[500, 502, 503, 504]) -session = requests.Session() -session.mount("https://", HTTPAdapter(max_retries=retries)) - - -def check_response(response): - try: - response.raise_for_status() - except requests.HTTPError: - print(response.json()) - raise - - -def submit_id_mapping(from_db, to_db, ids): - request = requests.post( - f"{API_URL}/idmapping/run", - data={"from": from_db, "to": to_db, "ids": ",".join(ids)}, - ) - check_response(request) - return request.json()["jobId"] - - -def get_next_link(headers): - re_next_link = re.compile(r'<(.+)>; rel="next"') - if "Link" in headers: - match = re_next_link.match(headers["Link"]) - if match: - return match.group(1) - - -def check_id_mapping_results_ready(job_id): - while True: - request = session.get(f"{API_URL}/idmapping/status/{job_id}") - check_response(request) - j = request.json() - if "jobStatus" in j: - if j["jobStatus"] == "RUNNING": - print(f"Retrying in {POLLING_INTERVAL}s") - time.sleep(POLLING_INTERVAL) - else: - raise Exception(j["jobStatus"]) - else: - return bool(j["results"] or j["failedIds"]) - - -def get_batch(batch_response, file_format, compressed): - batch_url = get_next_link(batch_response.headers) - while batch_url: - batch_response = session.get(batch_url) - batch_response.raise_for_status() - yield decode_results(batch_response, file_format, compressed) - batch_url = get_next_link(batch_response.headers) - - -def combine_batches(all_results, batch_results, file_format): - if file_format == "json": - for key in ("results", "failedIds"): - if key in batch_results and batch_results[key]: - all_results[key] += batch_results[key] - elif file_format == "tsv": - return all_results + batch_results[1:] - else: - return all_results + batch_results - return all_results - - -def get_id_mapping_results_link(job_id): - url = f"{API_URL}/idmapping/details/{job_id}" - request = session.get(url) - check_response(request) - return request.json()["redirectURL"] - - -def decode_results(response, file_format, compressed): - if compressed: - decompressed = zlib.decompress(response.content, 16 + zlib.MAX_WBITS) - if file_format == "json": - j = json.loads(decompressed.decode("utf-8")) - return j - elif file_format == "tsv": - return [line for line in decompressed.decode("utf-8").split("\n") if line] - elif file_format == "xlsx": - return [decompressed] - elif file_format == "xml": - return [decompressed.decode("utf-8")] - else: - return decompressed.decode("utf-8") - elif file_format == "json": - return response.json() - elif file_format == "tsv": - return [line for line in response.text.split("\n") if line] - elif file_format == "xlsx": - return [response.content] - elif file_format == "xml": - return [response.text] - return response.text - - -def get_xml_namespace(element): - m = re.match(r"\{(.*)\}", element.tag) - return m.groups()[0] if m else "" - - -def merge_xml_results(xml_results): - merged_root = ElementTree.fromstring(xml_results[0]) - for result in xml_results[1:]: - root = ElementTree.fromstring(result) - for child in root.findall("{http://uniprot.org/uniprot}entry"): - merged_root.insert(-1, child) - ElementTree.register_namespace("", get_xml_namespace(merged_root[0])) - return ElementTree.tostring(merged_root, encoding="utf-8", xml_declaration=True) - - -def print_progress_batches(batch_index, size, total): - n_fetched = min((batch_index + 1) * size, total) - print(f"Fetched: {n_fetched} / {total}") - - -def get_id_mapping_results_search(url): - parsed = urlparse(url) - query = parse_qs(parsed.query) - file_format = query["format"][0] if "format" in query else "json" - if "size" in query: - size = int(query["size"][0]) - else: - size = 500 - query["size"] = size - compressed = ( - query["compressed"][0].lower() == "true" if "compressed" in query else False - ) - parsed = parsed._replace(query=urlencode(query, doseq=True)) - url = parsed.geturl() - request = session.get(url) - check_response(request) - results = decode_results(request, file_format, compressed) - total = int(request.headers["x-total-results"]) - print_progress_batches(0, size, total) - for i, batch in enumerate(get_batch(request, file_format, compressed), 1): - results = combine_batches(results, batch, file_format) - print_progress_batches(i, size, total) - if file_format == "xml": - return merge_xml_results(results) - return results - - -def get_id_mapping_results_stream(url): - if "/stream/" not in url: - url = url.replace("/results/", "/results/stream/") - request = session.get(url) - check_response(request) - parsed = urlparse(url) - query = parse_qs(parsed.query) - file_format = query["format"][0] if "format" in query else "json" - compressed = ( - query["compressed"][0].lower() == "true" if "compressed" in query else False - ) - return decode_results(request, file_format, compressed) - - -def query_uniprot_id_mapping(query_list: list, FROM='UniProtKB_AC-ID', TO='Gene_Name', FORMAT='tab'): - """Query Uniprot ID mappings programatically (utility function) - See availabe mappings: https://www.uniprot.org/help/api_idmapping - Function is programmed to query gene IDs based on protein IDs. - - Parameters - ---------- - query_list : list - list of strings containing queries in format specified - in FROM parameter. - FROM : str, optional - Format of string-ids in query_list, by default 'ACC+ID' - TO : str, optional - Format to which strings-ids should be matched with, by default 'GENENAME' - FORMAT : str, optional - Separator for Uniprot-ID, by default 'tab' - - Returns - ------- - list: - List of tuples of type (FROM, TO) - """ - job_id = submit_id_mapping( - from_db=FROM, to_db=TO, ids=query_list - ) - if check_id_mapping_results_ready(job_id): - link = get_id_mapping_results_link(job_id) - results = get_id_mapping_results_search(link) - results = {d['from']: d['to'] for d in results['results']} - return results - - -if __name__ == "__main__": - ids = ['A0A075B6I0', 'A0A075B6I1', 'A0A075B6I6', 'A0A075B6I9',] - results = query_uniprot_id_mapping(ids) - print(results) - # {'A0A075B6I0': 'IGLV8-61', 'A0A075B6I1': 'IGLV4-60', 'A0A075B6I6': 'IGLV1-50', 'A0A075B6I9': 'IGLV7-46'} diff --git a/vaep/fasta.py b/vaep/fasta.py deleted file mode 100644 index bf1351ded..000000000 --- a/vaep/fasta.py +++ /dev/null @@ -1,163 +0,0 @@ -""" -Based on notebook received by [Annelaura Bach](https://www.cpr.ku.dk/staff/mann-group/?pure=en/persons/443836) -and created by Johannes B. Müller -[scholar](https://scholar.google.com/citations?user=Rn1OS8oAAAAJ&hl=de), -[MPI Biochemistry](https://www.biochem.mpg.de/person/93696/2253) -""" -import logging - -from tqdm import tqdm - -logger = logging.getLogger(__name__) - - -def get_n_miscleaved(pep_sequences: list, num_missed: int): - """Build miscleaved peptide sequences for a number of missed cleaving sides. - Call function recusively if you want not only a specific number of miscleavages.""" - _miscleaved = [] - for i in range(len(pep_sequences)): - if i >= num_missed: - _miscleaved.append(''.join(pep_sequences[i - num_missed:i + 1])) - return _miscleaved - - -def cleave_to_tryptic(seq, num_missed_cleavages=1, reversed=False, add_rxk=False): - """Takes a sequence and returns an array of peptides cleaved C-term to R and K. - - Parameters - ---------- - seq : str, optional - sequence of amino acids as string - num_missed_cleavages : int, optional - number of missed cleavages to consider, by default 1 - reversed : bool, optional - if reversed decoy peptide sequences should be added, by default False - """ - - seq.replace(' ', '') # remove white spaces - seq = seq.upper() - # add whitespace behind K and R for splitting - seq = seq.replace('K', 'K ').replace('R', 'R ').split() - - peps_seq = [seq, ] - - for i in range(1, num_missed_cleavages + 1): - _seq = get_n_miscleaved(seq, num_missed=i) - peps_seq.append(_seq) - - if add_rxk and num_missed_cleavages < 2: - _seq = find_rxk_peptides(seq) - peps_seq.append(_seq) - - return peps_seq - - -def find_rxk_peptides(l_peptides): - """Combine 3 peptides to one, if the first is an - 'RxK'-peptide: RX, XR, KX, XK - where the X can - be any other amino-acid. - - Returns - ------- - list - list of miscleaved peptides. Can be empty. - """ - if len(l_peptides) >= 3: - rdx_peptides = [] - for i in range(len(l_peptides) - 2): - if len(l_peptides[i]) <= 2: - rdx_peptides.append( - ''.join(l_peptides[i:i + 3]) - ) - return rdx_peptides - else: - return [] - - -def read_fasta(fp): - """Read a fasta file and yield continously header and sequences.""" - header, seq = None, [] - for line in fp: - line = line.rstrip() - if line.startswith(">"): - if header: - yield (header, ''.join(seq)) - header, seq = line, [] - else: - seq.append(line) - if header: - yield (header, ''.join(seq)) - - -def iterFlatten(root): - """Flatten a nested structure.""" - if isinstance(root, (list, tuple)): - for element in root: - for e in iterFlatten(element): - yield e - else: - yield root - - -def count_peptide_matches(peptide_to_proteinID: dict, - protein_to_gene: dict = None, - level: str = 'protein_id') -> dict: - """Count the number of matches of a peptide to the specified level. - Provides the basis for summary statistics (a counter of matches). - - Possibly to be extended in a class handling the matches of proteinIDs to - peptide sequences. - - Parameters - ---------- - peptide_to_proteinID : dict - mapping of peptides to a list of proteinIDs. - protein_to_gene : dict, optional - Uniport mapping of protein IDs (no isotopes ending "-2", "-3", etc) - in case of level='gene', by default None - level : str, optional - to which level the peptides should be matched. - 'protein_id', 'protein' or 'gene', by default 'protein_id' - - Returns - ------- - dict - Counter of number of matches of peptides to the specified level items. - {1 : 3, 3: 5} means that 3 peptides have been match uniquly to one item (e.g. gene) - and 5 peptides have been matched to 3 items (e.g. genes). - - Raises - ------ - KeyError - [description] - """ - assert level in ['protein_id', 'protein', 'gene'], ValueError( - 'Specify one of the three (in order of aggregation level): {}'.format( - ', '.join(['prot_id', 'prot', 'gene']))) - if level == 'gene': - assert protein_to_gene is not None, "Please provide protein to gene level name" - _set_missing_entires = set() - n_peptides_mapped_to_level = {} - - for _pep, _protein_ids in tqdm(peptide_to_proteinID.items()): - - if level == 'protein_id': - n_peptides_mapped_to_level[_pep] = len(_protein_ids) - elif level == 'protein': - n_peptides_mapped_to_level[_pep] = len( - {x.split('-')[0] for x in peptide_to_proteinID[_pep]}) - elif level == 'gene': - _proteins = {x.split('-')[0] for x in peptide_to_proteinID[_pep]} - _set_genes = set() - for _prot in _proteins: - try: - _set_genes.add(protein_to_gene[_prot]) - except KeyError: - _set_missing_entires.add(_prot) - n_peptides_mapped_to_level[_pep] = len(_set_genes) - else: - raise KeyError(f'unknown level: {level}') - if level == 'gene': - logger.warning( - f'Missing protein to gene mapppings: {len(set(_set_missing_entires))}') - return n_peptides_mapped_to_level diff --git a/vaep/io/data_objects.py b/vaep/io/data_objects.py deleted file mode 100644 index 9dcf988f1..000000000 --- a/vaep/io/data_objects.py +++ /dev/null @@ -1,693 +0,0 @@ -from collections import Counter -import os -import sys -import logging -import json -from pathlib import Path -import multiprocessing -from types import SimpleNamespace -from typing import Callable, Iterable, List, Union - -from tqdm.notebook import tqdm -import numpy as np -import pandas as pd - -from fastcore.meta import delegates - -from vaep.io import dump_json, dump_to_csv -import vaep.io.mq as mq -from vaep.io.mq import MaxQuantOutputDynamic -import vaep.pandas -from vaep.plotting import plot_feat_counts -# from .config import FOLDER_MQ_TXT_DATA, FOLDER_PROCESSED - -from fastcore.imports import IN_IPYTHON, IN_JUPYTER, IN_COLAB, IN_NOTEBOOK - -logger = logging.getLogger(__name__) -logger.info(f"Calling from {__name__}") - -FOLDER_DATA = Path('data') -FOLDER_DATA.mkdir(exist_ok=True) - -FOLDER_PROCESSED = FOLDER_DATA / 'processed' -FOLDER_PROCESSED.mkdir(exist_ok=True) - -FOLDER_MQ_TXT_DATA = FOLDER_DATA / 'mq_out' - - -# from vaep.cfg import DEFAULTS -DEFAULTS = SimpleNamespace() -DEFAULTS.ALL_SUMMARIES = Path(FOLDER_PROCESSED) / 'all_summaries.json' -DEFAULTS.COUNT_ALL_PEPTIDES = FOLDER_PROCESSED / 'count_all_peptides.json' - -# fastcore.imports has in_notebook, etc functionality -# IN_IPYTHON,IN_JUPYTER,IN_COLAB,IN_NOTEBOOK = in_ipython(),in_jupyter(),in_colab(),in_notebook() - -N_WORKERS_DEFAULT = os.cpu_count() - 1 if os.cpu_count() <= 16 else 16 -if sys.platform == 'win32' and IN_NOTEBOOK: - N_WORKERS_DEFAULT = 1 - logger.warn( - "only use main process due to issue with ipython and multiprocessing on Windows") - - -manager = multiprocessing.Manager() - - -def _convert_dtypes(df): - """Convert dtypes automatically and make string columns categories.""" - df = df.convert_dtypes() - l_string_columns = df.columns[df.dtypes == 'string'] - if not l_string_columns.empty: - df[l_string_columns] = df[l_string_columns].astype('category') - return df - - -def calc_chunksize(n_workers, len_iterable, factor=4): - """Calculate chunksize argument for Pool-methods. - - Source and reference: https://stackoverflow.com/a/54813527/9684872 - """ - chunksize, extra = divmod(len_iterable, n_workers * factor) - if extra: - chunksize += 1 - return chunksize - - -class col_summary: - MS = 'MS' - MS2 = 'MS/MS Identified' - - -class MqAllSummaries(): - - def __init__(self, fp_summaries=DEFAULTS.ALL_SUMMARIES): - fp_summaries = Path(fp_summaries) - if fp_summaries.exists(): - self.df = _convert_dtypes( - pd.read_json(fp_summaries, orient='index')) - print( - f"{self.__class__.__name__}: Load summaries of {len(self.df)} folders.") - else: - if not fp_summaries.parent.exists(): - raise FileNotFoundError( - f'Folder of filename not found: {fp_summaries.parent}') - self.df = None - self.fp_summaries = fp_summaries - self.usecolumns = col_summary() - - def __len__(self): - if self.df is not None: - return len(self.df) - else: - raise ValueError("No data loaded yet.") - - def load_summary(self, folder): - folder_name = folder.stem - try: - mq_output = MaxQuantOutputDynamic(folder) - # to_dict not very performant - return {folder_name: mq_output.summary.iloc[0].to_dict()} - except FileNotFoundError as e: - if not mq_output.files and len(list(mq_output.folder.iterdir())) == 0: - mq_output.folder.rmdir() - logger.warning(f'Remove empty folder: {mq_output}') - self.empty_folders.append(f"{folder_name}\n") - else: - logger.error(f"{mq_output}, No summary and not empty.") - return {} - - def load_new_samples(self, folders, workers: int = 1): - if self.df is not None: - d_summaries = self.df.to_dict(orient='index') - samples = set(folder.stem for folder in folders) - \ - set(d_summaries.keys()) - samples = [folder for folder in folders if folder.stem in samples] - else: - d_summaries = {} - samples = folders - if not hasattr(self, 'empty_folders'): - # should this depend on multiprocessing? - self.empty_folders = manager.list() - - if samples: - # process_chunch_fct = self.load_summary - # workers=workers - # desc = 'Load summaries' - if workers > 1: - with multiprocessing.Pool(workers) as p: - # set chunksize: https://stackoverflow.com/a/49533645/9684872 - chunksize = calc_chunksize(workers, len(samples), factor=2) - list_of_updates = list( - tqdm( - p.imap(self.load_summary, samples, - chunksize=chunksize), - total=len(samples), - desc='Load summaries')) - else: - list_of_updates = [self.load_summary( - folder) for folder in tqdm(samples)] - - print("Newly loaded samples:", len(list_of_updates)) - - for d in list_of_updates: - d_summaries.update(d) - - self.df = _convert_dtypes( - pd.DataFrame.from_dict(d_summaries, orient='index')) - self.save_state() - else: - print("No new sample added.") - return self.df - - def save_state(self): - """Save summaries DataFrame as json and pickled object.""" - self.df.to_json(self.fp_summaries, orient='index') - self.df.to_pickle(self.fp_summaries.parent / - f"{self.fp_summaries.stem}.pkl") - - def get_files_w_min_MS2(self, threshold=10_000, relativ_to=FOLDER_MQ_TXT_DATA): - """Get a list of file ids with a minimum MS2 observations.""" - threshold_ms2_identified = threshold - mask = self.df[self.usecolumns.MS2] > threshold_ms2_identified - print(f"Selected {mask.sum()} of {len(mask)} folders.") - return [Path(relativ_to) / folder for folder in self.df.loc[mask].index] - -# maybe move functions related to fnames - - -def get_fname(N, M): - """Helper function to get file for intensities""" - return f'df_intensities_N{N:05d}_M{M:05d}' - - -def get_folder_names(folders: Iterable[str]): - return set(Path(folder).stem for folder in folders) - - -def create_parent_folder_name(folder: Path) -> str: - return folder.stem[:4] - - -# plotting function for value_counts from FeatureCounter.get_df_counts - - -def collect_in_chuncks(paths: Iterable[Union[str, Path]], - process_chunk_fct: Callable, - n_workers: int = N_WORKERS_DEFAULT, - chunks=10, - desc='Run chunks in parallel') -> List: - """collect the results from process_chunk_fct (chunk of files to loop over). - The idea is that process_chunk_fct creates a more memory-efficient intermediate - result than possible if only callling single fpaths in paths. - - Parameters - ---------- - paths : Iterable - Iterable of paths - process_chunk_fct : Iterable[str, Path] - Callable which takes a chunk of paths and returns an result to collect, e.g. a dict - n_workers : int, optional - number of processes, by default N_WORKERS_DEFAULT - - Returns - ------- - List - List of results returned by process_chunk_fct - """ - paths_splits = np.array_split(paths, min(chunks, len(paths))) - if n_workers > 1: - with multiprocessing.Pool(n_workers) as p: - collected = list(tqdm(p.imap(process_chunk_fct, paths_splits), - total=len(paths_splits), - desc=desc)) - else: - collected = map(process_chunk_fct, paths_splits) - return collected - - -class FeatureCounter(): - def __init__(self, fp_counter: str, counting_fct: Callable[[List], Counter], - idx_names: Union[List, None] = None, - feature_name='feature', - overwrite=False): - self.fp = Path(fp_counter) - self.counting_fct = counting_fct - self.idx_names = idx_names - self.feature_name = feature_name - if self.fp.exists() and not overwrite: - d = self.load(self.fp) - self.counter = d['counter'] - self.loaded = set(folder for folder in d['based_on']) - self.dumps = d['dumps'] - else: - self.loaded = set() # None - self.counter = Counter() - self.dumps = dict() - - def __repr__(self): - return f"{self.__class__.__name__}(fp_counter={str(self.fp)})" - - def get_new_folders(self, folders: List[str]): - ret = get_folder_names(folders) - self.loaded - return ret - - # combine multiprocessing into base class? - def sum_over_files(self, folders: List[Path], n_workers=N_WORKERS_DEFAULT, save=True): - if self.loaded: - new_folder_names = self.get_new_folders(folders) - logger.info(f'{len(new_folder_names)} new folders to process.') - if new_folder_names: - folders = [ - folder for folder in folders if folder.stem in new_folder_names] - else: - folders = [] - - if folders: - list_of_sample_dicts = collect_in_chuncks(folders, - process_chunk_fct=self.counting_fct, - n_workers=n_workers, - chunks=n_workers * 3, - desc='Count features in 100 chunks') - - for d in tqdm(list_of_sample_dicts, - total=len(list_of_sample_dicts), - desc='combine counters from chunks'): - self.counter += d['counter'] - self.dumps.update(d['dumps']) - - if self.loaded: - self.loaded |= new_folder_names - else: - self.loaded = get_folder_names(folders) - if save: - self.save() - else: - logger.info('Nothing to process.') - return self.counter - - @property - def n_samples(self): - return len(self.loaded) - - def get_df_counts(self) -> pd.DataFrame: - """Counted features as DataFrame with proportion values. - - Returns - ------- - pd.DataFrame - _description_ - """ - feat_counts = (pd.Series(self.counter) - .sort_values(ascending=False) - .to_frame('counts')) - feat_counts['proportion'] = feat_counts / self.n_samples - if self.idx_names: - feat_counts.index.names = self.idx_names - feat_counts.reset_index(inplace=True) - feat_counts.index.name = 'consecutive count' - return feat_counts - - def plot_counts(self, df_counts: pd.DataFrame = None, ax=None, prop_feat=0.25, min_feat_prop=.01): - """Plot counts based on get_df_counts.""" - if df_counts is None: - df_counts = self.get_df_counts() - ax = plot_feat_counts(df_counts, - feat_name=self.feature_name, - n_samples=self.n_samples, - count_col='counts', - ax=ax) - n_feat_cutoff = vaep.pandas.get_last_index_matching_proportion( - df_counts=df_counts, prop=prop_feat) - n_samples_cutoff = df_counts.loc[n_feat_cutoff, 'counts'] - logger.info(f'{n_feat_cutoff = }, {n_samples_cutoff = }') - x_lim_max = vaep.pandas.get_last_index_matching_proportion( - df_counts, min_feat_prop) - logger.info(f'{x_lim_max = }') - ax.set_xlim(-1, x_lim_max) - ax.axvline(n_feat_cutoff, c='red') - - # ax.text(n_feat_cutoff + 0.03 * x_lim_max, - # n_samples_cutoff, '25% cutoff', - # style='italic', fontsize=12, - # bbox={'facecolor': 'grey', 'alpha': 0.5, 'pad': 10}) - - ax.annotate(f'{prop_feat*100}% cutoff', - xy=(n_feat_cutoff, n_samples_cutoff), - xytext=(n_feat_cutoff + 0.1 * x_lim_max, n_samples_cutoff), - fontsize=16, - arrowprops=dict(facecolor='black', shrink=0.05)) - - return ax - - def save(self): - """Save state - - { - 'counter': Counter, - 'based_on': list, - 'dumps: dict, - } - """ - d = {'counter': self.counter, - 'based_on': list(self.loaded), - 'dumps': {k: str(v) for k, v in self.dumps.items()}} - logger.info(f"Save to: {self.fp}") - dump_json(d, filename=self.fp) - - def load(self, fp): - with open(self.fp) as f: - d = json.load(f) - d['counter'] = Counter(d['counter']) - d['dumps'] = {k: Path(v) for k, v in d['dumps'].items()} - return d - - def load_dump(self, fpath, fct=pd.read_csv, use_cols=None): - return fct(fpath, index=self.idx_names, usecols=None) - - -class Count(): - - def __init__(self, - process_folder_fct: Callable, - use_cols=None, - parent_folder_fct: Callable = create_parent_folder_name, - outfolder=FOLDER_PROCESSED / 'dumps', - dump=False): - self.outfolder = Path(outfolder) - self.outfolder.mkdir(exist_ok=True, parents=True) - self.use_cols = use_cols - self.process_folder_fct = process_folder_fct - self.parent_folder_fct = parent_folder_fct - self.dump = dump - - def __call__(self, folders, - **fct_args): - logging.debug( - f"Passed function arguments for process_folder_fct Callable: {fct_args}") - c = Counter() - fpath_dict = {} - for folder in tqdm(folders): - folder = Path(folder) - df = self.process_folder_fct( - folder=folder, use_cols=self.use_cols, **fct_args) - c.update(df.index) - if self.dump: - fpath_dict[folder.stem] = dump_to_csv(df, folder=folder, outfolder=self.outfolder, - parent_folder_fct=self.parent_folder_fct) - ret = {'counter': c, 'dumps': fpath_dict} - return ret - -# aggregated peptides - - -# # check df for redundant information (same feature value for all entries) -usecols = mq.COLS_ + ['Potential contaminant', 'Reverse', mq.mq_col.SEQUENCE, 'PEP', - 'id', 'Protein group IDs', 'Evidence IDs',] - - -def select_peptides(peptides: pd.DataFrame) -> pd.DataFrame: - mask = ((peptides[mq.mq_col.INTENSITY] == 0) - | (peptides["Potential contaminant"] == '+') - | (peptides["Reverse"] == '+') - ) - peptides = peptides.loc[~mask] - return peptides - - -def load_process_peptides(folder: Path, use_cols): - peptides = pd.read_table(folder / 'peptides.txt', - usecols=use_cols, - index_col=0, - low_memory=False) - peptides = select_peptides(peptides) - return peptides.drop(['Potential contaminant', 'Reverse'], axis=1) - - -def count_peptides(folders: List[Path], dump=True, - usecols=usecols, - parent_folder_fct: Callable = create_parent_folder_name, - outfolder=FOLDER_PROCESSED / 'agg_peptides_dumps'): - c = Counter() - fpath_dict = {} - for folder in folders: - peptides = load_process_peptides(folder, usecols) - c.update(peptides.index) - if dump: - fpath_dict[folder.stem] = dump_to_csv(peptides, - folder=folder, outfolder=outfolder, - parent_folder_fct=parent_folder_fct) - ret = {'counter': c, 'dumps': fpath_dict} - return ret - - -d_dtypes_training_sample = { - 'Sequence': pd.StringDtype(), - 'Proteins': pd.StringDtype(), - 'PEP': pd.Float32Dtype(), - 'Leading razor protein': pd.StringDtype(), - 'Gene names': pd.StringDtype(), - 'Intensity': pd.Int64Dtype() -} - - -def load_agg_peptide_dump(fpath): - fpath = Path(fpath) - peptides = pd.read_csv(fpath, index_col=0, dtype=d_dtypes_training_sample) - return peptides - - -@delegates() -class PeptideCounter(FeatureCounter): - - def __init__(self, - fp_counter: str, - counting_fct: Callable[[List], Counter] = count_peptides, - idx_names=['Sequence'], - feature_name='aggregated peptide', - **kwargs): - super().__init__(fp_counter, counting_fct=counting_fct, - idx_names=idx_names, feature_name=feature_name, **kwargs) - - @staticmethod - def load_dump(fpath): - return load_agg_peptide_dump(fpath) - - -# Evidence -evidence_cols = mq.mq_evidence_cols - - -def select_evidence(df_evidence: pd.DataFrame) -> pd.DataFrame: - mask = ((df_evidence[['Reverse', 'Potential contaminant']] - .notna() - .any(axis=1)) - | (df_evidence[evidence_cols.Intensity] == 0) - ) - evidence = df_evidence.loc[~mask].drop( - [evidence_cols.Potential_contaminant, - evidence_cols.Reverse], axis=1) - evidence = evidence.dropna(subset=[evidence_cols.Intensity]) - return evidence - - -idx_columns_evidence = [evidence_cols.Sequence, evidence_cols.Charge] - - -def load_process_evidence(folder: Path, use_cols, select_by): - evidence = pd.read_table(folder / 'evidence.txt', - usecols=idx_columns_evidence + use_cols, - low_memory=False) - evidence = select_evidence(evidence) - evidence = vaep.pandas.select_max_by( - evidence, grouping_columns=idx_columns_evidence, selection_column=select_by) - evidence = evidence.set_index(idx_columns_evidence).sort_index() - return evidence - - -def count_evidence(folders: List[Path], - select_by: str = 'Score', - dump=True, - use_cols=[evidence_cols.mz, - evidence_cols.id, - evidence_cols.Peptide_ID, - evidence_cols.Protein_group_IDs, - evidence_cols.Intensity, - evidence_cols.Score, - evidence_cols.Potential_contaminant, - evidence_cols.Reverse, - ], - parent_folder_fct: Callable = create_parent_folder_name, - outfolder=FOLDER_PROCESSED / 'evidence_dumps'): - outfolder = Path(outfolder) - outfolder.mkdir(exist_ok=True, parents=True) - c = Counter() - if dump: - fpath_dict = {} - for folder in tqdm(folders): - folder = Path(folder) - evidence = load_process_evidence( - folder=folder, use_cols=use_cols, select_by=select_by) - c.update(evidence.index) - if dump: - fpath_dict[folder.stem] = dump_to_csv(evidence, folder=folder, outfolder=outfolder, - parent_folder_fct=parent_folder_fct) - ret = {'counter': c, 'dumps': fpath_dict} - return ret - - -@delegates() -class EvidenceCounter(FeatureCounter): - - def __init__(self, fp_counter: str, - counting_fct: Callable[[List], Counter] = count_evidence, - idx_names=['Sequence', 'Charge'], - feature_name='charged peptide', - **kwargs): - super().__init__(fp_counter, counting_fct, - idx_names=idx_names, feature_name=feature_name, **kwargs) - - # Methods should use super, otherwise non-specific duplication is needed. - def save(self): - """Save state - - { - 'counter': Counter with tuple keys, - 'based_on': list - } - """ - d = {'counter': vaep.pandas.create_dict_of_dicts(self.counter), - 'based_on': list(self.loaded), - 'dumps': {k: str(v) for k, v in self.dumps.items()}} - print(f"Save to: {self.fp}") - dump_json(d, filename=self.fp) - - def load(self, fp): - with open(self.fp) as f: - d = json.load(f) - d['counter'] = Counter( - vaep.pandas.flatten_dict_of_dicts(d['counter'])) - d['dumps'] = {k: Path(v) for k, v in d['dumps'].items()} - return d - - -def load_evidence_dump(fpath, index_col=['Sequence', 'Charge']): - df = pd.read_csv(fpath, index_col=index_col) - return df - -# Protein Groups - - -pg_cols = mq.mq_protein_groups_cols - -# def load_process_evidence(folder: Path, use_cols, select_by): - - -def load_and_process_proteinGroups(folder: Union[str, Path], - # use_cols not really a parameter (or needs asserts?) - use_cols: List = [ - pg_cols.Protein_IDs, - pg_cols.Majority_protein_IDs, - pg_cols.id, - pg_cols.Gene_names, - pg_cols.Evidence_IDs, - pg_cols.Q_value, - pg_cols.Score, - pg_cols.Only_identified_by_site, - pg_cols.Reverse, - pg_cols.Potential_contaminant, - pg_cols.Intensity, -]): - folder = Path(folder) - pg = pd.read_table(folder / 'proteinGroups.txt', - usecols=use_cols, - low_memory=False) - mask = pg[[pg_cols.Only_identified_by_site, pg_cols.Reverse, - pg_cols.Potential_contaminant]].notna().any(axis=1) - pg = pg.loc[~mask] - mask = pg[pg_cols.Intensity] > 1 - pg = pg.loc[mask] - gene_set = pg[pg_cols.Gene_names].str.split(';') - col_loc_gene_names = pg.columns.get_loc(pg_cols.Gene_names) - _ = pg.insert(col_loc_gene_names + 1, 'Number of Genes', - gene_set.apply(vaep.pandas.length)) - mask_no_gene = pg[pg_cols.Gene_names].isna() - pg_no_gene = pg.loc[mask_no_gene] - logger.debug(f"Entries without any gene annotation: {len(pg_no_gene)}") - pg = vaep.pandas.select_max_by(df=pg.loc[~mask_no_gene], - grouping_columns=[pg_cols.Gene_names], - selection_column=pg_cols.Score) - pg = pd.concat([pg, pg_no_gene]) - pg = pg.set_index(pg_cols.Protein_IDs) - pg = pg.drop([pg_cols.Only_identified_by_site, - pg_cols.Reverse, - pg_cols.Potential_contaminant,], - axis=1) - return pg - - -count_protein_groups = Count(load_and_process_proteinGroups, - use_cols=[ - pg_cols.Protein_IDs, - pg_cols.Majority_protein_IDs, - pg_cols.Gene_names, - pg_cols.Evidence_IDs, - pg_cols.Q_value, - pg_cols.Score, - pg_cols.Only_identified_by_site, - pg_cols.Reverse, - pg_cols.Potential_contaminant, - pg_cols.Intensity, - ], - outfolder=FOLDER_PROCESSED / 'proteinGroups_dumps', - dump=True) - - -@delegates() -class ProteinGroupsCounter(FeatureCounter): - - def __init__(self, fp_counter: str, - counting_fct: Callable[[List], - Counter] = count_protein_groups, - idx_names=[pg_cols.Protein_IDs], # mq_specfic - feature_name='protein group', - **kwargs): - super().__init__(fp_counter, counting_fct, idx_names=idx_names, - feature_name=feature_name, **kwargs) - - -def load_pg_dump(folder, use_cols=None): - logger.debug(f"Load: {folder}") - df = pd.read_csv(folder, index_col=pg_cols.Protein_IDs, usecols=use_cols) - return df - -# Gene Counter - - -def pg_idx_gene_fct(folder: Union[str, Path], use_cols=None): - folder = Path(folder) - logger.debug(f"Load: {folder}") - df = pd.read_csv(folder, index_col=pg_cols.Gene_names, usecols=use_cols) - return df - - -count_genes = Count(pg_idx_gene_fct, - use_cols=[ - pg_cols.Protein_IDs, - pg_cols.Gene_names, - pg_cols.Intensity, - ], - outfolder=FOLDER_PROCESSED / 'gene_dumps', # don't dump, only read - dump=False) - - -# summing needs to be done over processed proteinGroup dumps -@delegates() -class GeneCounter(FeatureCounter): - """Gene Counter to count gene in dumped proteinGroups.""" - - def __init__(self, fp_counter: str, - counting_fct: Callable[[List], Counter] = count_genes, - feature_name='gene', - idx_names=['Gene names'], **kwargs): - super().__init__(fp_counter, counting_fct, idx_names=idx_names, - feature_name=feature_name, **kwargs) diff --git a/vaep/io/filenames.py b/vaep/io/filenames.py deleted file mode 100644 index d6338e6d7..000000000 --- a/vaep/io/filenames.py +++ /dev/null @@ -1,16 +0,0 @@ -import re -import logging -import functools - -logger = logging.getLogger(__name__) - - -def read_number_from_str(fname: str, regex: str = 'M[0-9]*', strip: int = 1) -> int: - M = re.search(regex, fname).group() - logger.info(f"Found: {M}") - M = int(M[strip:]) - return M - - -read_M_features = functools.partial(read_number_from_str, regex='M[0-9]*', strip=1) -read_N_samples = functools.partial(read_number_from_str, regex='N[0-9]*', strip=1) diff --git a/vaep/io/mq.py b/vaep/io/mq.py deleted file mode 100644 index 3bae23ff1..000000000 --- a/vaep/io/mq.py +++ /dev/null @@ -1,694 +0,0 @@ -import logging -from collections import Counter, namedtuple -from pathlib import Path -from typing import Iterable -import omegaconf - -import pandas as pd -from pandas import Int64Dtype, StringDtype, Float64Dtype - -import vaep.io - -logger = logging.getLogger(__name__) -logger.addHandler(logging.NullHandler()) - - -mq_use_columns = ['Gene names', - 'Intensity', - 'Retention time', - 'Calibrated retention time', - 'Sequence', - 'Leading razor protein', - 'Proteins' - ] - -MqColumnsUsed = namedtuple(typename='MqColumns', - field_names=[ - s.upper().replace(' ', '_') for s in mq_use_columns - ]) -mq_col = MqColumnsUsed(*mq_use_columns) - -FASTA_KEYS = ["Proteins", "Gene names"] - -mq_evidence_cols = {'Sequence': 'Sequence', - 'Length': 'Length', - 'Modifications': 'Modifications', - 'Modified_sequence': 'Modified sequence', - 'Oxidation_M_Probabilities': 'Oxidation (M) Probabilities', - 'Oxidation_M_Score_Diffs': 'Oxidation (M) Score Diffs', - 'Acetyl_Protein_N-term': 'Acetyl (Protein N-term)', - 'Oxidation_M': 'Oxidation (M)', - 'Missed_cleavages': 'Missed cleavages', - 'Proteins': 'Proteins', - 'Leading_proteins': 'Leading proteins', - 'Leading_razor_protein': 'Leading razor protein', - 'Gene_names': 'Gene names', - 'Protein_names': 'Protein names', - 'Type': 'Type', - 'Raw_file': 'Raw file', - 'MSMS_mz': 'MS/MS m/z', - 'Charge': 'Charge', - 'mz': 'm/z', - 'Mass': 'Mass', - 'Uncalibrated_-_Calibrated_mz_[ppm]': 'Uncalibrated - Calibrated m/z [ppm]', - 'Uncalibrated_-_Calibrated_mz_[Da]': 'Uncalibrated - Calibrated m/z [Da]', - 'Mass_error_[ppm]': 'Mass error [ppm]', - 'Mass_error_[Da]': 'Mass error [Da]', - 'Uncalibrated_mass_error_[ppm]': 'Uncalibrated mass error [ppm]', - 'Uncalibrated_mass_error_[Da]': 'Uncalibrated mass error [Da]', - 'Max_intensity_mz_0': 'Max intensity m/z 0', - 'Retention_time': 'Retention time', - 'Retention_length': 'Retention length', - 'Calibrated_retention_time': 'Calibrated retention time', - 'Calibrated_retention_time_start': - 'Calibrated retention time start', - 'Calibrated_retention_time_finish': 'Calibrated retention time finish', - 'Retention_time_calibration': 'Retention time calibration', - 'Match_time_difference': 'Match time difference', - 'Match_mz_difference': 'Match m/z difference', - 'Match_q-value': 'Match q-value', - 'Match_score': 'Match score', - 'Number_of_data_points': 'Number of data points', - 'Number_of_scans': 'Number of scans', - 'Number_of_isotopic_peaks': 'Number of isotopic peaks', - 'PIF': 'PIF', - 'Fraction_of_total_spectrum': 'Fraction of total spectrum', - 'Base_peak_fraction': 'Base peak fraction', - 'PEP': 'PEP', - 'MSMS_count': 'MS/MS count', - 'MSMS_scan_number': 'MS/MS scan number', - 'Score': 'Score', - 'Delta_score': 'Delta score', - 'Combinatorics': 'Combinatorics', - 'Intensity': 'Intensity', - 'Reverse': 'Reverse', - 'Potential_contaminant': 'Potential contaminant', - 'id': 'id', - 'Protein_group_IDs': 'Protein group IDs', - 'Peptide_ID': 'Peptide ID', - 'Mod._peptide_ID': 'Mod. peptide ID', - 'MSMS_IDs': 'MS/MS IDs', - 'Best_MSMS': 'Best MS/MS', - 'Oxidation_M_site_IDs': 'Oxidation (M) site IDs', - 'Taxonomy_IDs': 'Taxonomy IDs'} - -mq_evidence_cols = omegaconf.OmegaConf.create(mq_evidence_cols) - - -mq_evidence_dtypes = {'Length': Int64Dtype(), - 'Modifications': StringDtype, - 'Modified sequence': StringDtype, - 'Oxidation (M) Probabilities': StringDtype, - 'Oxidation (M) Score Diffs': StringDtype, - 'Acetyl (Protein N-term)': Int64Dtype(), - 'Oxidation (M)': Int64Dtype(), - 'Missed cleavages': Int64Dtype(), - 'Proteins': StringDtype, - 'Leading proteins': StringDtype, - 'Leading razor protein': StringDtype, - 'Gene names': StringDtype, - 'Protein names': StringDtype, - 'Type': StringDtype, - 'Raw file': StringDtype, - 'MS/MS m/z': Float64Dtype(), - 'm/z': Float64Dtype(), - 'Mass': Float64Dtype(), - 'Uncalibrated - Calibrated m/z [ppm]': Float64Dtype(), - 'Uncalibrated - Calibrated m/z [Da]': Float64Dtype(), - 'Mass error [ppm]': Float64Dtype(), - 'Mass error [Da]': Float64Dtype(), - 'Uncalibrated mass error [ppm]': Float64Dtype(), - 'Uncalibrated mass error [Da]': Float64Dtype(), - 'Max intensity m/z 0': Float64Dtype(), - 'Retention time': Float64Dtype(), - 'Retention length': Float64Dtype(), - 'Calibrated retention time': Float64Dtype(), - 'Calibrated retention time start': Float64Dtype(), - 'Calibrated retention time finish': Float64Dtype(), - 'Retention time calibration': Float64Dtype(), - 'Match time difference': Int64Dtype(), - 'Match m/z difference': Int64Dtype(), - 'Match q-value': Int64Dtype(), - 'Match score': Int64Dtype(), - 'Number of data points': Int64Dtype(), - 'Number of scans': Int64Dtype(), - 'Number of isotopic peaks': Int64Dtype(), - 'PIF': Int64Dtype(), - 'Fraction of total spectrum': Int64Dtype(), - 'Base peak fraction': Int64Dtype(), - 'PEP': Float64Dtype(), - 'MS/MS count': Int64Dtype(), - 'MS/MS scan number': Int64Dtype(), - 'Score': Float64Dtype(), - 'Delta score': Float64Dtype(), - 'Combinatorics': Int64Dtype(), - 'Intensity': Int64Dtype(), - 'Reverse': Int64Dtype(), - 'Potential contaminant': Int64Dtype(), - 'id': Int64Dtype(), - 'Protein group IDs': StringDtype, - 'Peptide ID': Int64Dtype(), - 'Mod. peptide ID': Int64Dtype(), - 'MS/MS IDs': StringDtype, - 'Best MS/MS': Int64Dtype(), - 'Oxidation (M) site IDs': StringDtype, - 'Taxonomy IDs': StringDtype, - } - - -mq_protein_groups_cols = {'Protein_IDs': 'Protein IDs', - 'Majority_protein_IDs': 'Majority protein IDs', - 'Peptide_counts_all': 'Peptide counts (all)', - 'Peptide_counts_razor+unique': 'Peptide counts (razor+unique)', - 'Peptide_counts_unique': 'Peptide counts (unique)', - 'Protein_names': 'Protein names', - 'Gene_names': 'Gene names', - 'Fasta_headers': 'Fasta headers', - 'Number_of_proteins': 'Number of proteins', - 'Peptides': 'Peptides', - 'Razor_+_unique_peptides': 'Razor + unique peptides', - 'Unique_peptides': 'Unique peptides', - 'Sequence_coverage_[%]': 'Sequence coverage [%]', - 'Unique_+_razor_sequence_coverage_[%]': 'Unique + razor sequence coverage [%]', - 'Unique_sequence_coverage_[%]': 'Unique sequence coverage [%]', - 'Mol._weight_[kDa]': 'Mol. weight [kDa]', - 'Sequence_length': 'Sequence length', - 'Sequence_lengths': 'Sequence lengths', - 'Q_value': 'Q-value', - 'Score': 'Score', - 'Intensity': 'Intensity', - 'MSMS_count': 'MS/MS count', - 'Only_identified_by_site': 'Only identified by site', - 'Reverse': 'Reverse', - 'Potential_contaminant': 'Potential contaminant', - 'id': 'id', - 'Peptide_IDs': 'Peptide IDs', - 'Peptide_is_razor': 'Peptide is razor', - 'Mod._peptide_IDs': 'Mod. peptide IDs', - 'Evidence_IDs': 'Evidence IDs', - 'MSMS_IDs': 'MS/MS IDs', - 'Best_MSMS': 'Best MS/MS', - 'Oxidation_M_site_IDs': 'Oxidation (M) site IDs', - 'Oxidation_M_site_positions': 'Oxidation (M) site positions', - 'Taxonomy_IDs': 'Taxonomy IDs'} - -mq_protein_groups_cols = omegaconf.OmegaConf.create(mq_protein_groups_cols) - -########################################################################################## -########################################################################################## -# import abc # abc.ABCMeta ? - - -class MaxQuantOutput(): - """Class assisting with MaxQuant txt output folder. - - Parameters - ---------- - folder: pathlib.Path, str - Path to Maxquant `txt` output folder. - - - Attributes - ---------- - self.files : list - list of files in `folder`. - _inital_attritubutes : list - Initial set of non-magic attributes - NAME_FILE_MAP : dict - Keys for known MaxQuant output files. - """ - NAME_FILE_MAP = {'allPeptides': 'allPeptides.txt', - 'evidence': 'evidence.txt', - 'matchedFeatures': 'matchedFeatures.txt', - 'modificationSpecificPeptides': 'modificationSpecificPeptides.txt', - 'ms3Scans': 'ms3Scans.txt', - 'msms': 'msms.txt', - 'msmsScans': 'msmsScans.txt', - 'mzRange': 'mzRange.txt', - 'OxidationSites': 'Oxidation (M)Sites.txt', - 'parameters': 'parameters.txt', - 'peptides': 'peptides.txt', - 'proteinGroups': 'proteinGroups.txt', - 'summary': 'summary.txt'} - - def __init__(self, folder): - self.folder = Path(folder) - self.files = self.get_files() - - def get_files(self): - """Get all txt files in output folder - - Attributes - --------- - paths: NamedTuple - """ - self.paths = vaep.io.search_files(path=self.folder, query='.txt') - return self.paths.files - - @classmethod - def register_file(cls, filename): - - @property - def fct(cls): - return cls.find_attribute(f'_{filename}') - - return fct - - def find_attribute(self, filename): - """Look up or load attribute.""" - if not hasattr(self, filename): - df = self.load(filename[1:]) - setattr(self, filename, df) - return getattr(self, filename) - - def load(self, file): - """Load a specified file into memory and return it. - Can be used """ - filepath = self.folder / self.NAME_FILE_MAP[file] - if not Path(filepath).exists(): - raise FileNotFoundError( - f"No such file: {file}.txt: Choose one of the following {', '.join(self.files)}") - - return pd.read_table(filepath, index_col=0) - - # def dump_training_data(self, ) - - def get_list_of_attributes(self): - """Return current list on non-magic instance attributes.""" - return [x for x in dir(self) if not x.startswith('__')] - - def __repr__(self): - return f'{self.__class__.__name__}({self.folder!r})' - - def dump_intensity(self, folder='.'): - """Dump all intensity values from peptides.txt""" - folder = Path(folder) - folder.mkdir(exist_ok=True) - fname = folder / f"{self.folder.stem}.json" - vaep.io.dump_json( - data_dict=self.peptides.Intensity.dropna().to_dict(), - filename=fname) - logger.info(f'Dumped intensities in peptides.txt: {fname}.') - - # needed to reset attributes on instance creation. - _inital_attritubutes = [x for x in dir() if not x.startswith('__')] - - -# register all properties -# Would be great to be able to do this at runtime based on the files actually present. -for filename in MaxQuantOutput.NAME_FILE_MAP.keys(): - setattr(MaxQuantOutput, filename, MaxQuantOutput.register_file(filename)) - -# This version offers less inspection possibilities as the attributes are only set when they are looked up. - - -class MaxQuantOutputDynamic(MaxQuantOutput): - """Class assisting with MaxQuant txt output folder. Fetches only availabe txt files. - - Parameters - ---------- - folder: pathlib.Path, str - Path to Maxquant `txt` output folder. - - Attributes - --------- - files : list - file names on disk - file_keys : list - keys for file name on disk to use for lookup - name_file_map : dict - Keys for known MaxQuant output files. - _inital_attritubutes : list - Initial set of non-magic attributes - """ - - def __init__(self, folder): - super().__init__(folder) - - # patch properties at instance creation? - self.name_file_map = {} - for file in self.files: - file_key = Path(file).stem - for symbol in " ()": - file_key = file_key.replace(symbol, '') - self.name_file_map[file_key] = file - self.file_keys = list(self.name_file_map) - - def __getattr__(self, filename): - if filename in self.name_file_map: - df = self.load(filename) - setattr(self, filename, df) - else: - msg = f"No such file: {filename}.txt: Choose one of the following:\n{', '.join(self.file_keys)}" - raise AttributeError(msg) - return df - - # needed to reset attributes on instance creation. - _inital_attritubutes = [x for x in dir() if not x.startswith('__')] - -########################################################################################## -########################################################################################## - - -def check_df(df, columns): - """Check DataFrame for specified columns - - Parameters - ---------- - df : pandas.DataFrame - DataFrame for which should contain `columns`. - columns : Iterable - Iterable of column names. - - Raises - ------ - AttributeError - One or more `columns` are missing. Specifies which. - """ - - missing = [] - for col in columns: - if col not in df: - missing.append(col) - - if missing: - raise AttributeError(f'Missing column(s): {", ".join(missing)}') - - -COLS_ = [mq_col.INTENSITY, mq_col.LEADING_RAZOR_PROTEIN] + FASTA_KEYS - - -def get_peptides_with_single_gene(peptides, keep_columns=COLS_, gene_column=mq_col.GENE_NAMES): - """Get long-data-format. Ungroup gene names. Peptides "shared" by genes - are assigned individual rows. retains only cases with full list of - features provided by `keep_columns`. - - Parameters - ---------- - peptides: pandas.DataFrame - MaxQuant txt output loaded as `pandas.DataFrame`. - keep_columns: list - List of columns to keep from the `peptides`.txt, default - {cols_} - gene_column: str - Column containing group information of format "group1;group2", - i.e. in MQ for genes "gene1;gene2". - """.format(cols_=COLS_) - if gene_column not in keep_columns: - keep_columns.append(gene_column) - check_df(peptides, COLS_) - peptides_with_single_gene = peptides[COLS_].dropna(how='any') - if len(peptides) < len(peptides_with_single_gene): - logger.warning('Removed {} of {} entries due to missing values.'.format( - len(peptides) - len(peptides_with_single_gene), - len(peptides) - )) - peptides_with_single_gene[gene_column] = peptides_with_single_gene[gene_column].str.split( - ';') - peptides_with_single_gene = peptides_with_single_gene.explode( - column=gene_column) - return peptides_with_single_gene - - -def get_set_of_genes(iterable, sep_in_str: str = ';'): - "Return the set of unique strings for an Iterable of strings (gene names)." - genes_single_unique = set() - for gene_iterable in pd.Series(iterable).str.split(sep_in_str): - try: - genes_single_unique.update(gene_iterable) - except TypeError: - pass - return genes_single_unique - - -def validate_gene_set(n_gene_single_unique, n_gene_sets): - """Compare N single geens to number of unqiue gene sets. - - Parameters - ---------- - n_gene_single_unique : int - Count in set. - n_gene_sets : int - Count in set. - - Raises - ------ - ValueError - [description] - """ - if n_gene_single_unique < n_gene_sets: - print( - f'There are however less unique-single genes {n_gene_single_unique} than sets.') - elif n_gene_single_unique == n_gene_sets: - print(f'Only realy unique gene (sets)') - else: - raise ValueError( - f'There are more gene-sets than unique genes: {n_gene_sets} vs. {n_gene_single_unique}.') - - -def count_genes_in_sets(gene_sets, sep=';'): - """Count for an Iterable of gene_sets - - Parameters - ---------- - gene_sets : Iterable - Iterable of gene_sets which entries are separated with `sep` - sep : str - Seperator of gene sets, default ';' - - Returns - ------- - collections.Counter - Counter with keys as genes and counts as value. - """ - genes_counted_each_in_unique_sets = Counter() - - for gene in pd.Series(gene_sets).dropna(): - try: - gene_iterable = gene.split(sep) - genes_counted_each_in_unique_sets.update(gene_iterable) - except TypeError: - print(f"Error on: {gene}") - - return genes_counted_each_in_unique_sets - - -def get_identifier_from_column(df: pd.DataFrame, identifier_col: str): - """Get unique identifier in a column of a DataFrame. - - Parameters - ---------- - df : pd.DataFrame - (Sub-) DataFrame with data for a gene. - identifier_col : str - Column name in which unique identifier is suspected - - Returns - ------- - Any - unique identifier in `identifier_col` - - Raises - ------ - ValueError - Non-unique identifier in column - """ - identifier = df[identifier_col].unique() - if len(identifier) == 1: - identifier = identifier[0] - else: - raise ValueError( - f"Found {len(identifier)} non-unique identifier: {identifier}") - return identifier - - -def find_exact_cleaved_peptides_for_razor_protein(gene_data, fasta_db, gene_id: str = None): - """Find exactly cleaved peptides based on razor protein in provided data-set - - Parameters - ---------- - gene_data : pandas.DataFrame - Pandas DataFrame with information from MQ peptides.txt output table. - gene_data.columns.name should be set to gene names of gene_data. - fasta_db : dict - Created fasta database with specific scheme. - gene_id : str, optional - gene name, by default None - - Returns - ------- - list - list of exact peptides for the razor protein of the gene. - - Raises - ------ - ValueError - Raised if no unique gene identifier could be inferred from the data if no gene-id - was set. - KeyError - If no protein could be found in fasta_db for specified gene. - """ - # ToDo: Replace with config from package - KEY_PEPTIDES = 'peptides' - - if not isinstance(gene_data.columns.name, str) or not gene_id: - try: - gene_id = get_identifier_from_column(gene_data, mq_col.GENE_NAMES) - except ValueError as e: - raise ValueError( - f"Could not identify single, unique identifier from {gene_id} column: {e}" - "Please set columns.name feature to a string-identifier (for genes separated by ;)" - f" not of {type(gene_data.columns.name)}: {gene_data.columns.name}") - protein_id = gene_data[mq_col.LEADING_RAZOR_PROTEIN].unique() - - # ToDo: Check for all proteins and decide on the best? - if len(protein_id) != 1: - logger.warning("- Gene: {:8}: More than one razor protein (try first): {} (Gene: {}) ".format( - gene_id, ", ".join(x for x in protein_id), gene_data.columns.name)) - protein_id = protein_id[0] - try: - peps_exact_cleaved = fasta_db[protein_id][KEY_PEPTIDES][0] - except KeyError: - # MQ marks potential contaminent proteins - if 'CON__' in protein_id: - logger.info( - f"- Gene: {gene_id:8}: " - f"Potential contaminent protein is leading razor protein: {protein_id}" - f" (Gene: {gene_data.columns.name})") - elif 'REV__' in protein_id: - logger.info( - f"- Gene: {gene_id:8}: " - f"Reversed protein is leading razor protein: {protein_id}" - f" (Gene: {gene_data.columns.name})") - else: - raise ValueError(f'Check case for {gene_id} on {protein_id}.') - # assert len(gene_data[mq_col.PROTEINS].unique()) == 1, f"{gene_data[mq_col.PROTEINS].unique()}" - protein_sets = gene_data[mq_col.PROTEINS].unique() - if len(protein_sets) > 1: - logger.warning( - f"More than one set of genes: {gene_data[mq_col.PROTEINS].unique()}") - # ToDo: find intersection of proteins between all sequences. - - # Enforce: proteins have to be share between all peptides - protein_sets = [set.split(';') for set in protein_sets] - # ToDo: Check if ordering is relevant (if not all proteins are checked) - proteins_shared_by_all = set( - protein_sets.pop()).intersection(*protein_sets) - # ToDo: Some CON_ proteins are also present in the fasta and appear twice. - # Remove all CON__ proteins from data globally, including their fasta - # pendants (e.g. Keratin: Q04695;CON__Q04695) - # exclude potential other contaminents - protein_sets = [ - x for x in proteins_shared_by_all if 'CON__' not in x] # .sorted() - if len(protein_sets) == 0: - # raise KeyError("No other overall protein found for sequences.") - logger.warning( - f'No good protein found for gene ({gene_id:8}). Return empty list.') - return [] - if len(protein_sets) > 1: - logger.warning( - f"- Gene: {gene_id:8}: " - "Non-unique other protein set found (select first): {}".format( - ', '.join(protein_sets) - )) - protein_id = protein_sets.pop() - peps_exact_cleaved = fasta_db[protein_id][KEY_PEPTIDES][0] - return peps_exact_cleaved - - -def calculate_completness_for_sample( - peps_exact_cleaved: Iterable[str], - peps_in_data: Iterable[str]): - """Calculate completeness for set of peptides. - - Parameters - ---------- - peps_exact_cleaved : Iterable[str] - Iterable of peptides exactly cleaved - peps_in_data : Iterable[str] - Iterable of peptides found during a run / in a sample. Check if peptides - overlap with any of the exact peptides. - - Returns - ------- - float - proportion of exact peptides for which some evidence was found. - """ - c = 0 - if not peps_exact_cleaved: - return 0 # no exact peptides - for i, _pep in enumerate(peps_exact_cleaved): - logger.debug(f"Check if exact peptide matches: {_pep}") - for _found_pep in peps_in_data: - logger.debug(f"Check for peptide: {_found_pep}") - if _pep in _found_pep: - c += 1 - break - if c == len(peps_in_data): - logger.debug(f"Last checked peptides in position {i:2}: {_pep}") - logger.debug( - f"Searched therfore {i+1:2} out of {len(peps_exact_cleaved)} peptides, " - f"i.e. a share of {(i+1)/len(peps_exact_cleaved):.3f}") - break - return c / len(peps_exact_cleaved) - - -class ExtractFromPeptidesTxt(): - """Strategy to extract Intensity measurements from MaxQuant txt output peptides.txt. - Creates dump of Training Data. - """ - - def __init__(self, - out_folder, - mq_output_object: MaxQuantOutput, - # Could be made a certain type -> ensure schema is met. - fasta_db: dict - ): - # # ToDo: make this check work - assert isinstance(mq_output_object, MaxQuantOutput) - self._mq_output = mq_output_object - self.out_folder = Path(out_folder) / mq_output_object.folder.stem - self.out_folder.mkdir(exist_ok=True, parents=True) - self.fname_template = '{gene}.json' - self.fasta_db = fasta_db - - def __call__(self): - """Dump valid cases to file. - - Returns: - collections.Counter - Counter with gene IDs as key and completeness as value. - """ - _counter = 0 - _genes = dict() - peptides_with_single_gene = get_peptides_with_single_gene( - peptides=self._mq_output.peptides) - for gene_names, data_gene in peptides_with_single_gene.groupby(mq_col.GENE_NAMES): - data_gene.columns.name = gene_names # ToDo: Find better solution - peps_exact_cleaved = find_exact_cleaved_peptides_for_razor_protein( - data_gene, fasta_db=self.fasta_db) - c = calculate_completness_for_sample(peps_exact_cleaved=peps_exact_cleaved, - peps_in_data=data_gene.index) - assert gene_names not in _genes - _genes[gene_names] = c - # ToDo check completeness for each shared protein in list - if c >= .6: - fname = self.out_folder / \ - self.fname_template.format(gene=gene_names) - with open(fname, 'w') as f: - data_gene.to_json(f) - _counter += 1 - logger.info( - f'Dumped {_counter} genes from {self._mq_output.folder.stem}') - fname = self.out_folder / '0_completeness_all_genes.json' - vaep.io.dump_json(_genes, fname) - logger.info(f'Dumped files to: {str(self.out_folder)}') - return _genes - - def __repr__(self): - return f"{self.__class__.__name__}(out_folder={self.out_folder}, mq_output_object={repr(self._mq_output)}, fasta_db)" - - -# so MaxQuantOutput could know which strategy to apply for which file-type? -STRATEGIES = {'peptides.txt': '', - 'evidence.txt': ''} diff --git a/vaep/io/rawfiles.py b/vaep/io/rawfiles.py deleted file mode 100644 index 04df932cf..000000000 --- a/vaep/io/rawfiles.py +++ /dev/null @@ -1,116 +0,0 @@ -import os -from pathlib import Path, PurePosixPath - -from IPython.display import display -import ipywidgets as widgets -import pandas as pd - - -queries = set() - - -def find_indices_containing_query(query, X): - mask = X.index.str.contains(query) - X_query = X.loc[mask].sort_index() - queries.add(query) - return X_query - - -def get_unique_stem(query, index: pd.Index): - """Gets stem filename, by splitting filename left of query and remove last underscore _. - - Fractionated samples seem to be named by fraction type. Last field indicates fraction. - """ - ret = index.str.split(query).str[0].str.rsplit("_", n=1).str[0] - # ret = index.str.rsplit('_', n=1).str[0] - return sorted(list(set(ret))) - - -def show_fractions(stub: str, df): - subset = df[df.index.str.contains(stub)] - print(repr(stub)) - display(subset) - display(f"N: {len(subset)}") - - -class RawFileViewer: - def __init__(self, df: pd.DataFrame, start_query: str = "[Ff]rac", outputfolder: str = '.', path_col='path'): - """Indices are used.""" - self.df = df - self.file_names = df.index - # self.queries = set() # add query button - - self.w_query = widgets.Text(start_query) - self.query = start_query - - self.save_button = widgets.Button(description='Save current files.') - self.save_button.on_click(self.save_current_files) - - self.w_data = widgets.Dropdown( - options=self.get_options(self.w_query.value), index=0 - ) - self.stub = None - self.folder = Path(outputfolder) - self.path_col = path_col - - def get_options(self, query): - # this needs to be clearer - try: - sub_df = self.find_indices_containing_query(query) - ret = get_unique_stem(query, sub_df.index) - return ret - except BaseException: - print(f"Not a valid query: {query} ") - return () - - def save_current_files(self, button): - """Save files in current views as txt file. - """ - folder = Path(self.folder) / self.query - folder.mkdir(exist_ok=True) - fname = folder / f"{self.stub}.txt" - files = self.subset[self.path_col] - line_template = "-get {remote_path} {local_path}" - with open(fname, 'w') as f: - f.write(f'-lmkdir {self.stub}\n') - for _path in files: - _local_path = PurePosixPath(self.stub) / _path.name - _remote_path = PurePosixPath(_path) - line = line_template.format(remote_path=_remote_path, local_path=_local_path) - f.write(f'{line}\n') - print(f"Saved file paths to: {fname}") - - def viewer(self, query, stub: str): - if query != self.query: - self.query = query - print(f"updated query to: {query}") - self.w_data.options = self.get_options(query) - if len(self.w_data.options): - stub = self.w_data.options[0] - else: - print(f"Nothing to display for QUERY: {query}") - stub = None - # find_indices_containing_query = partial(find_indices_containing_query, X=data_unique) - if stub and stub != self.stub: - try: - subset = self.df[self.df.index.str.contains(stub)] - print('current stub: ', repr(stub)) - display(subset) - display(f"N: {len(subset)}") - self.subset = subset - except TypeError: - print(f"Nothing to display for query: {query}") - self.stub = stub - - def find_indices_containing_query(self, query): - mask = self.df.index.str.contains(query) - X_query = self.df.loc[mask].sort_index() - return X_query - - def view(self): - """Interactive viewer. Updates list of options based on query.""" - # widget for type of data: meta or not. might be combined - self.out_sel = widgets.interactive_output( - self.viewer, {"stub": self.w_data, "query": self.w_query} - ) - return widgets.VBox([self.w_query, self.w_data, self.out_sel, self.save_button]) # repr of class diff --git a/vaep/io/thermo_raw_files.py b/vaep/io/thermo_raw_files.py deleted file mode 100644 index 4bebfb58a..000000000 --- a/vaep/io/thermo_raw_files.py +++ /dev/null @@ -1,25 +0,0 @@ -cols_instrument = ['Thermo Scientific instrument model', - 'instrument attribute', - 'instrument serial number', ] - - -meta_raw_selected = [ - 'Content Creation Date', - 'Thermo Scientific instrument model', - 'instrument serial number', - 'Software Version', - 'Number of MS1 spectra', - 'Number of MS2 spectra', - 'Number of scans', - 'MS max charge', - 'MS max RT', - 'MS min MZ', - 'MS max MZ', - 'MS scan range', - 'mass resolution', - 'Retention time range', - 'Mz range', - 'beam-type collision-induced dissociation', - 'injection volume setting', - 'dilution factor', -] diff --git a/vaep/pandas/__init__.py b/vaep/pandas/__init__.py index 489765682..5557cbd58 100644 --- a/vaep/pandas/__init__.py +++ b/vaep/pandas/__init__.py @@ -1,9 +1,9 @@ import collections.abc from collections import namedtuple -import numbers + from types import SimpleNamespace -import typing + from typing import Iterable import numpy as np @@ -40,20 +40,6 @@ def combine_value_counts(X: pd.DataFrame, dropna=True) -> pd.DataFrame: return freq_targets -def counts_with_proportion(s: pd.Series) -> pd.DataFrame: - """Counts with proportion of counts(!). - - Note: In case of missing values the proportion is not based on the total number of - rows in the DataFrame. - """ - s = s.value_counts() - s.index.name = 'value' - N = s.sum() - ret = s.to_frame('counts') - ret['prop.'] = s / N - return ret - - def unique_cols(s: pd.Series) -> bool: """Check all entries are equal in pandas.Series @@ -72,13 +58,6 @@ def unique_cols(s: pd.Series) -> bool: return (s.iloc[0] == s).all() -def show_columns_with_variation(df: pd.DataFrame) -> pd.DataFrame: - df_describe = df.describe(include='all') - col_mask = (df_describe.loc['unique'] > 1) | ( - df_describe.loc['std'] > 0.01) - return df.loc[:, col_mask] - - def get_unique_non_unique_columns(df: pd.DataFrame) -> SimpleNamespace: """Get back a namespace with an column.Index both of the unique and non-unique columns. @@ -228,30 +207,6 @@ def interpolate(wide_df: pd.DataFrame, name='interpolated') -> pd.DataFrame: return ret -def create_dict_of_dicts(d: dict, verbose=False, - # maybe this should not be here... - transform_values: typing.Union[typing.Callable, numbers.Number] = None): - """Unpack a dictionary with tuple keys to a nested dictonary - of single tuple keys. - """ - ret = dict() - for keys, v in d.items(): - if verbose: - print(f"current key: {str(keys):90}: {len(v):>5}") - current_dict = ret - for k in keys[:-1]: - if k not in current_dict: - current_dict[k] = dict() - current_dict = current_dict[k] - last_key = keys[-1] - if last_key not in current_dict: - current_dict[last_key] = transform_values( - v) if transform_values else v - else: - raise KeyError(f"Key already in dict: {last_key}") - return ret - - def flatten_dict_of_dicts(d: dict, parent_key: str = '') -> dict: """Build tuples for nested dictionaries for use as `pandas.MultiIndex`. diff --git a/vaep/tests/test_fasta.py b/vaep/tests/test_fasta.py deleted file mode 100644 index 194636498..000000000 --- a/vaep/tests/test_fasta.py +++ /dev/null @@ -1,47 +0,0 @@ -from vaep.fasta import get_n_miscleaved -from vaep.fasta import find_rxk_peptides -from vaep.fasta import count_peptide_matches - - -def test_get_n_miscleaved_miss_1(): - pep_seqs = ['MSSHEGGK', 'K', 'K', 'ALK', 'QPK', 'K', 'QAK', - 'EMDEEEK', 'AFK', - 'QK', 'QK', 'EEQK', 'K', 'LEVLK', 'AK', - 'VVGK', 'GPLATGGIK', 'K', 'SGK', 'K'] - - true_result = set(['MSSHEGGKK', 'KK', 'KALK', 'ALKQPK', 'QPKK', 'KQAK', 'QAKEMDEEEK', - 'EMDEEEKAFK', 'AFKQK', - 'QKQK', 'QKEEQK', 'EEQKK', 'KLEVLK', 'LEVLKAK', 'AKVVGK', - 'VVGKGPLATGGIK', 'GPLATGGIKK', 'KSGK', 'SGKK']) - - result = get_n_miscleaved(pep_sequences=pep_seqs, num_missed=1) - - assert len(true_result.difference(result)) == 0, print( - true_result.difference(result)) - - -def test_find_rxk_peptides(): - - pep_seqs = ['MSSHEGGK', 'K', 'K', 'ALK', 'QPK', 'K', 'QAK', 'EMDEEEK', 'AFK', - 'QK', 'QK', 'EEQK', 'K', 'LEVLK', 'AK', 'VVGK', 'GPLATGGIK', 'K', 'SGK', 'K'] - - true_rdx_peps = ['KKALK', 'KALKQPK', 'KQAKEMDEEEK', 'QKQKEEQK', - 'QKEEQKK', 'KLEVLKAK', 'AKVVGKGPLATGGIK', 'KSGKK'] - - assert true_rdx_peps == find_rxk_peptides( - pep_seqs), 'Build sequence: {}'.format(repr(find_rxk_peptides(pep_seqs))) - - -def test_count_pep_mapped_to_gene(): - test_peptide_to_proteinID = {'LMHIQPPK': [ - 'A0JLT2', 'A0A2R8YDL4', 'A0A494C0G4', 'A0A494C0Y4', 'A0JLT2-2', 'J3KR33']} - test_protein_to_gene = {'A0JLT2': 'MED19', 'J3KR33': 'MED19'} - - assert count_peptide_matches( - test_peptide_to_proteinID, test_protein_to_gene) == {'LMHIQPPK': 6} - - assert count_peptide_matches(test_peptide_to_proteinID, test_protein_to_gene, level='protein') == { - 'LMHIQPPK': 5}, 'Error for canonical protein level (combination of all isotopes in UniProt)' - - assert count_peptide_matches( - test_peptide_to_proteinID, test_protein_to_gene, level='gene') == {'LMHIQPPK': 1} diff --git a/vaep/tests/test_pandas.py b/vaep/tests/test_pandas.py index 7f66e1431..4d46cc2f7 100644 --- a/vaep/tests/test_pandas.py +++ b/vaep/tests/test_pandas.py @@ -53,30 +53,6 @@ def test_flatten_dict_of_dicts(): assert expected == actual -def test_create_dict_of_dicts(): - data = {('a', 'a1', 'a2'): 1, - ('a', 'a1', 'a3'): 2, - ('b', 'b1', 'b2'): 3, - ('b', 'b1', 'b3'): 4} - expected = { - "a": {'a1': {'a2': 1, 'a3': 2}}, - "b": {'b1': {'b2': 3, 'b3': 4}} - } - actual = vaep.pandas.create_dict_of_dicts(data) - assert expected == actual - - data = {('a', 'a1', 'a2'): (1, 1), - ('a', 'a1', 'a3'): (2, 2), - ('b', 'b1', 'b2'): (3, 3), - ('b', 'b1', 'b3'): (4, 4)} - expected = { - "a": {'a1': {'a2': [1, 1], 'a3': [2, 2]}}, - "b": {'b1': {'b2': [3, 3], 'b3': [4, 4]}} - } - actual = vaep.pandas.create_dict_of_dicts(data, transform_values=list) - assert expected == actual - - def test_key_map(): # Build a schema of dicts d = {'one': {'alpha': {'a': 0.5, 'b': 0.3}}, diff --git a/vaep/tests/test_utils.py b/vaep/tests/test_utils.py index 3191e9678..c6bad659f 100644 --- a/vaep/tests/test_utils.py +++ b/vaep/tests/test_utils.py @@ -1,8 +1,5 @@ import pathlib -from vaep.utils import append_to_filepath, sample_iterable - -# def test_sample_iterable(): -# pass +from vaep.utils import append_to_filepath def test_append_to_filepath(): diff --git a/vaep/utils.py b/vaep/utils.py index d0ac0810e..245ba5088 100644 --- a/vaep/utils.py +++ b/vaep/utils.py @@ -1,4 +1,3 @@ -from random import sample import pathlib from typing import Union import numpy as np @@ -7,14 +6,6 @@ from vaep.io.datasplits import long_format -def sample_iterable(iterable: dict, n=10) -> list: - """Sample some keys from a given dictionary.""" - n_examples_ = n if len(iterable) > n else len(iterable) - keys = list(iterable) - sample_ = sample(keys, n_examples_) - return sample_ - - def append_to_filepath(filepath: Union[pathlib.Path, str], to_append: str, sep: str = '_', diff --git a/workflows/README.md b/workflows/README.md deleted file mode 100644 index f7962031c..000000000 --- a/workflows/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Workflows - -## Snakemake -Snakemake is a framework for execution of workflows on UNIX based systems. -It is written in the line of thought of -[`GNU Makefiles`](https://www.opensourceforu.com/2012/06/gnu-make-in-detail-for-beginners/), -but as an extension to Python rather than `C/C++`. - -### Setup -``` -conda install -n snakemake snakemake pygraphviz -``` - -## Interacting with erda - -### Setup -In your `~/.ssh/config` define a target, here the `SharedFolderName` is called by `hela`: - -``` -Host hela -Hostname io.erda.dk -VerifyHostKeyDNS yes -User SharedFolderName -``` - -### Connect interactively - -Then you can connect to `hela` using the `sftp`-command, and copy files to your -local `data`-folder: - -``` -sftp -B 258048 hela # pw is SharedFolderName -get file1.raw data/ -get file2.raw data/ -``` - -### In Shell Script - -### In Python Script -Checkout snakemake's [SFTP](https://snakemake.readthedocs.io/en/stable/snakefiles/remote_files.html#file-transfer-over-ssh-sftp) -functionality which uses [`pysftp`](https://pysftp.readthedocs.io/en/release_0.2.8/pysftp.html#pysftp.Connection). - - -## Get file list from folder - -Once you have some files uploaded to erda, once in a while you could check which files -you already did store there. Assuming you followed the previous setup step, using the -hostname `io.erda.dk`, you can query the files in a `directory` and store the to a file -named `files_and_folders_in_dir.txt`: - -`sftp -q io.erda.dk:directory/ <<< "ls" | grep -v '^sftp>' > files_and_folders_in_dir.txt` - -### Examples and log - -``` -sftp -q hela <<< "ls" | grep -v '^sftp>' > hela_files.txt -sftp -q io.erda.dk:share_hela_raw/MNT_2019_Proteomics/MNT/ <<< "ls" | grep -v '^sftp>' > hela_mnt_2019.txt -sftp -q io.erda.dk:share_hela_raw/MNT_2020_MM/ <<< "ls" | grep -v '^sftp>' > hela_mnt_2020.txt -sftp -q io.erda.dk:share_hela_raw/MNT_2019_Clinical_Proteomics/MNT/ <<< "ls" | grep -v '^sftp>' > hela_mnt_2019_clinical_proteomics.txt -sftp -q io.erda.dk:share_hela_raw/MNT_2017_Proteomics/ <<< "ls" | grep -v '^sftp>' > hela_mnt_2017_proteomics.txt -sftp -q io.erda.dk:share_hela_raw/MNT_2017_Clinical_Proteomics/ <<< "ls" | grep -v '^sftp>' > hela_mnt_2017_clinical_proteomics.txt -sftp -q io.erda.dk:share_hela_raw/MNT_2013_Proteomics/ <<< "ls" | grep -v '^sftp>' > hela_mnt_2013_proteomics.txt -sftp -q io.erda.dk:share_hela_raw/MNT_2018_Proteomics/ <<< "ls" | grep -v '^sftp>' > hela_mnt_2018_proteomics.txt -sftp -q io.erda.dk:share_hela_raw/MNT_2018_Clinical_Proteomics/ <<< "ls" | grep -v '^sftp>' > hela_mnt_2018_clinical_proteomics.txt -sftp -q io.erda.dk:share_hela_raw/MNT_2016_Proteomics/ <<< "ls -S" | grep -v '^sftp>' > hela_mnt_2016_proteomics.txt -sftp -q io.erda.dk:share_hela_raw/MNT_2015_Proteomics/ <<< "ls -S" | grep -v '^sftp>' > hela_mnt_2015_proteomics.txt -``` - -get a list of all files in the `mq_out` folder on erda (the default folder for storing results): - -``` -sftp -q io.erda.dk:mq_out/ <<< "ls" | grep -v '^sftp>' > hela_processed.txt -``` \ No newline at end of file diff --git a/workflows/hela_files.txt b/workflows/hela_files.txt deleted file mode 100644 index 462f47fcb..000000000 --- a/workflows/hela_files.txt +++ /dev/null @@ -1,552 +0,0 @@ -20180721_QX7_IgPa_MA_HeLa_500ng_LC12_13.raw -20190416_QX2_ChDe_MA_HeLa_500ng_LC05_CTCDoff_190418180742.raw -20190416_QX3_MiWi_MA_Hela_500ng_LC15.raw -20190416_QX7_AnPi_MA_HeLa_500ng_LC01.raw -20190417_QX0_MaTa_MA_HeLa_500ng_LC07_1_too_much_for_a_cleaned_MS.raw -20190417_QX4_JoSw_MA_HeLa_500ng_BR13_standard.raw -20190417_QX4_JoSw_MA_HeLa_500ng_BR14_new.raw -20190417_QX7_JuSc_MA_HeLa_500ng_LC01.raw -20190418_QX1_JoMu_MA_HeLa_500ng_LC11.raw -20190418_QX8_JuSc_MA_HeLa_500ng_1.raw -20190422_QX3_MaTa_MA_Br14_Hela_500ng_LC15.raw -20190422_QX8_JuSc_MA_HeLa_500ng_1.raw -20190423_QX0_MaPe_MA_HeLa_500ng_LC07_1_high.raw -20190423_QX2_FlMe_MA_HeLa_500ng_LC05_CTCDoff.raw -20190423_QX6_MaTa_MA_HeLa_Br13_500ng_LC09.raw -20190423_QX6_MaTa_MA_HeLa_Br13_500ng_LC09_20190423174837.raw -20190423_QX6_MaTa_MA_HeLa_Br14_500ng_DIA_LC09.raw -20190423_QX7_JuSc_MA_HeLaBr14_500ng_LC02.raw -20190423_QX7_JuSc_MA_HeLa_500ng_LC01.raw -20190424_QX2_FlMe_MA_HeLa_500ng_LC05_CTCDoff.raw -20190424_QX8_JuSc_MA_HeLa_500ng_1.raw -20190425_QX3_MaTa_MA_Hela_500ng_LC15.raw -20190425_QX4_JoSw_MA_HeLa_500ng_BR13_standard.raw -20190425_QX4_JoSw_MA_HeLa_500ng_BR13_standard_190425181909.raw -20190425_QX4_JoSw_MA_HeLa_500ng_BR13_standard_190426221220.raw -20190425_QX7_ChDe_MA_HeLaBr14_500ng_LC02.raw -20190425_QX7_ChDe_MA_HeLa_500ng_LC01.raw -20190425_QX8_JuSc_MA_HeLa_500ng_1.raw -20190426_QX1_JoMu_MA_HeLa_500ng_LC11.raw -20190426_QX2_FlMe_MA_HeLa_500ng_LC05_CTCDoff_newcol.raw -20190426_QX2_FlMe_MA_HeLa_500ng_LC05_CTCDoff_newcol_190426220210.raw -20190428_QX1_JoMu_MA_HeLa_Easy11_uPAC_500ng.raw -20190428_QX1_JoMu_MA_HeLa_Easy11_uPAC_500ng_190428112836.raw -20190429_QX0_ChDe_MA_HeLa_500ng_LC07_1_BR13.raw -20190429_QX0_ChDe_MA_HeLa_500ng_LC07_1_BR13_190507121913.raw -20190429_QX0_ChDe_MA_HeLa_500ng_LC07_1_BR14.raw -20190429_QX2_ChDe_MA_HeLa_500ng_LC05_CTCDoff_BR14.raw -20190429_QX2_ChDe_MA_HeLa_500ng_LC05_CTCDoff_newcol.raw -20190429_QX3_ChDe_MA_Hela_500ng_LC15.raw -20190429_QX3_ChDe_MA_Hela_500ng_LC15_190429151336.raw -20190429_QX4_ChDe_MA_HeLa_500ng_BR13_standard.raw -20190429_QX4_ChDe_MA_HeLa_500ng_BR13_standard_190501203657.raw -20190429_QX4_ChDe_MA_HeLa_500ng_BR14_standard.raw -20190429_QX6_ChDe_MA_HeLa_Br13_500ng_LC09.raw -20190429_QX6_ChDe_MA_HeLa_Br14_500ng_LC09.raw -20190430_QX6_ChDe_MA_HeLa_Br13_500ng_LC09.raw -20190430_QX6_ChDe_MA_HeLa_Br14_500ng_LC09.raw -20190501_QX8_MiWi_MA_HeLa_500ng_new.raw -20190501_QX8_MiWi_MA_HeLa_500ng_old.raw -20190502_QX7_ChDe_MA_HeLaBr14_500ng.raw -20190502_QX7_ChDe_MA_HeLa_500ng.raw -20190502_QX8_MiWi_MA_HeLa_500ng_new.raw -20190502_QX8_MiWi_MA_HeLa_500ng_old.raw -20190503_QX1_LiSc_MA_HeLa_500ng_LC10.raw -20190506_QX2_FlMe_MA_HeLa_500ng_LC05_CTCDoff_1.raw -20190506_QX2_FlMe_MA_HeLa_500ng_LC05_CTCDoff_2.raw -20190506_QX3_ChDe_MA_Hela_500ng_LC15.raw -20190506_QX4_JiYu_MA_HeLa_500ng_BR13_standard.raw -20190506_QX6_ChDe_MA_HeLa_Br13_500ng_LC09.raw -20190506_QX7_ChDe_MA_HeLaBr14_500ng.raw -20190506_QX7_ChDe_MA_HeLa_500ng.raw -20190506_QX8_MiWi_MA_HeLa_500ng_new.raw -20190506_QX8_MiWi_MA_HeLa_500ng_old.raw -20190507_QX4_JiYu_MA_HeLa_500ng_BR14_standard.raw -20190507_QX6_ChDe_MA_HeLa_Br13_500ng_LC09.raw -20190508_QX2_FlMe_MA_HeLa_500ng_LC05_CTCDoff_1.raw -20190509_QX6_ChDe_MA_HeLa_Br14_500ng_LC09.raw -20190509_QX6_ChDe_MA_HeLa_Br14_500ng_LC09_20190509120700.raw -20190510_QX0_ChDe_MA_HeLa_500ng_LC07_1_BR14.raw -20190511_QX0_ChDe_MA_HeLa_500ng_LC07_1_BR14.raw -20190513_QX1_LiSc_MA_HeLa_500ng_LC10.raw -20190513_QX2_SeVW_MA_HeLa_500ng_LC05_CTCDoff_1.raw -20190513_QX3_ChDe_MA_Hela_500ng_LC15.raw -20190513_QX7_ChDe_MA_HeLaBr14_500ng.raw -20190513_QX8_MiWi_MA_HeLa_BR14_500ng.raw -20190514_QX0_MaPe_MA_HeLa_500ng_LC07_1_BR14.raw -20190514_QX1_JoMu_MA_HeLa_500ng_LC10_DMSO.raw -20190514_QX1_JoMu_MA_HeLa_500ng_LC10_DMSO_190514213034.raw -20190514_QX4_JiYu_MA_HeLa_500ng.raw -20190514_QX4_JiYu_MA_HeLa_500ng_BR14.raw -20190514_QX6_ChDe_MA_HeLa_Br13_500ng_LC09.raw -20190514_QX6_ChDe_MA_HeLa_Br14_500ng_LC09.raw -20190514_QX6_ChDe_MA_HeLa_Br14_500ng_LC09_20190515085753.raw -20190515_QX3_AsJa_MA_Hela_500ng_LC15.raw -20190515_QX4_JiYu_MA_HeLa_500ng_BR14.raw -20190515_QX6_ChDe_MA_HeLa_Br14_500ng_LC09.raw -20190515_QX8_MiWi_MA_HeLa_BR14_500ng.raw -20190515_QX8_MiWi_MA_HeLa_BR14_500ng_190516123056.raw -20190516_QX0_AlRe_MA_HeLa_500ng_LC07_1_BR14.raw -20190516_QX0_AlRe_MA_HeLa_500ng_LC07_1_BR14_190516181021.raw -20190516_QX4_JiYu_MA_HeLa_500ng_BR14.raw -20190516_QX4_JiYu_MA_HeLa_500ng_BR14_190518195426.raw -20190517_QX0_AlRe_MA_HeLa_500ng_LC07_1_BR14.raw -20190517_QX8_MiWi_MA_HeLa_BR14_500ng.raw -20190520_QX1_JoMu_MA_HeLa_500ng_LC10_DMSO.raw -20190520_QX2_SeVW_MA_HeLa_500ng_LC05_CTCDoff_1.raw -20190520_QX3_LiSc_MA_Hela_500ng_LC15.raw -20190520_QX4_JoSw_MA_HeLa_500ng.raw -20190521_QX0_MaPe_MA_HeLa_500ng_LC07_1_BR14.raw -20190521_QX0_MaPe_MA_HeLa_500ng_LC07_1_BR14_190521192614.raw -20190521_QX1_LiSc_MA_HeLa_500ng_LC14.raw -20190521_QX3_LiSc_MA_Hela_500ng_LC15.raw -20190521_QX4_JoSw_MA_HeLa_500ng.raw -20190521_QX6_AsJa_MA_HeLa_Br14_500ng_LC09.raw -20190521_QX6_AsJa_MA_HeLa_Br14_500ng_LC09_20190522134621.raw -20190521_QX7_MaMu_MA_HeLaBr14_500ng.raw -20190521_QX8_MiWi_MA_HeLa_BR14_500ng.raw -20190522_QX0_MaPe_MA_HeLa_500ng_LC07_1_BR14.raw -20190522_QX0_MaPe_MA_HeLa_500ng_LC07_1_BR14_190524170803.raw -20190523_QX3_LiSc_MA_Hela_500ng_LC15.raw -20190523_QX8_MiWi_MA_HeLa_BR14_500ng.raw -20190523_QX8_MiWi_MA_HeLa_BR14_500ng_08isolation.raw -20190524_QX4_JoSw_MA_HeLa_500ng.raw -20190525_QX1_PhGe_MA_HeLa_500ng_LC10.raw -20190525_QX1_PhGe_MA_HeLa_500ng_LC10_190525140733.raw -20190525_QX1_PhGe_MA_HeLa_500ng_LC10_190526143611.raw -20190525_QX1_PhGe_MA_HeLa_500ng_LC10_190526151124.raw -20190526_QX4_LiSc_MA_HeLa_500ng.raw -20190526_QX8_IgPa_MA_HeLa_BR14_500ng.raw -20190526_QX8_IgPa_MA_HeLa_BR14_500ng_08isolation.raw -20190527_QX0_MaPe_MA_HeLa_500ng_LC07_1_BR14.raw -20190527_QX1_PhGe_MA_HeLa_500ng_LC10.raw -20190527_QX3_LiSc_MA_Hela_500ng_LC15.raw -20190527_QX3_LiSc_MA_Hela_500ng_LC15_190527171650.raw -20190527_QX4_IgPa_MA_HeLa_500ng.raw -20190527_QX7_MaMu_MA_HeLa_Br14_500ng.raw -20190528_QX1_PhGe_MA_HeLa_500ng_LC10.raw -20190528_QX1_PhGe_MA_HeLa_DMSO_500ng_LC14.raw -20190528_QX1_PhGe_MA_HeLa_DMSO_500ng_LC14_190528164924.raw -20190528_QX1_PhGe_MA_HeLa_DMSO_500ng_LC14_190528191042.raw -20190528_QX2_SeVW_MA_HeLa_500ng_LC05_CTCDoff_1.raw -20190528_QX6_AsJa_MA_HeLa_Br14_500ng_LC09.raw -20190528_QX6_AsJa_MA_HeLa_Br14_500ng_LC09_2nd.raw -20190528_QX8_MiWi_MA_HeLa_BR14_500ng.raw -20190528_QX8_MiWi_MA_HeLa_BR14_500ng_190531131859.raw -20190530_QX2_SeVW_MA_HeLa_500ng_LC05_CTCDoff_1.raw -20190530_QX4_IgPa_MA_HeLa_500ng.raw -20190530_QX6_AsJa_MA_HeLa_Br14_500ng_LC09.raw -20190531_QX3_AnSe_MA_Hela_500ng_LC15.raw -20190531_QX8_MiWi_MA_HeLa_BR14_500ng.raw -20190601_QX1_JoMu_MA_HeLa_DMSO_500ng_LC14.raw -20190603_QX0_MePh_MA_HeLa_500ng_LC07_1_BR14.raw -20190603_QX3_AnSe_MA_Hela_500ng_LC15.raw -20190603_QX3_AnSe_MA_Hela_500ng_LC15_190603172414.raw -20190603_QX4_JiYu_MA_HeLa_500ng.raw -20190603_QX7_IgPa_MA_HeLa_Br14_500ng.raw -20190603_QX7_IgPa_MA_HeLa_Br14_500ng_190607132950.raw -20190604_QX8_MiWi_MA_HeLa_BR14_500ng.raw -20190605_QX0_MePh_MA_HeLa_500ng_LC07_1_BR14.raw -20190605_QX0_MePh_MA_HeLa_500ng_LC07_1_BR14_190610203402.raw -20190605_QX3_ChDe_MA_Hela_500ng_LC15.raw -20190606_QX4_JiYu_MA_HeLa_500ng.raw -20190606_QX8_MiWi_MA_HeLa_BR14_500ng.raw -20190607_QX4_JiYu_MA_HeLa_500ng.raw -20190609_QX8_MiWi_MA_HeLa_BR14_500ng.raw -20190609_QX8_MiWi_MA_HeLa_BR14_500ng_190609195817.raw -20190609_QX8_MiWi_MA_HeLa_BR14_500ng_190625163359.raw -20190609_QX8_MiWi_MA_HeLa_BR14_500ng_190625212127.raw -20190610_QX1_JoMu_MA_HeLa_DMSO_500ng_LC14.raw -20190611_QX0_AnBr_MA_HeLa_500ng_LC07_1.raw -20190611_QX0_AnBr_MA_HeLa_500ng_LC07_2.raw -20190611_QX0_MaTa_MA_HeLa_500ng_LC07_1.raw -20190611_QX0_MePh_MA_HeLa_500ng_LC07_1.raw -20190611_QX0_MePh_MA_HeLa_500ng_LC07_1_190618114751.raw -20190611_QX0_MePh_MA_HeLa_500ng_LC07_2.raw -20190611_QX0_MePh_MA_HeLa_500ng_LC07_3.raw -20190611_QX0_MePh_MA_HeLa_500ng_LC07_4.raw -20190611_QX0_MePh_MA_HeLa_500ng_LC07_5.raw -20190611_QX2_SeVW_MA_HeLa_500ng_LC05_CTCDoff_1.raw -20190611_QX3_LiSc_MA_Hela_500ng_LC15.raw -20190611_QX4_JiYu_MA_HeLa_500ng.raw -20190611_QX7_IgPa_MA_HeLa_Br14_500ng.raw -20190611_QX7_IgPa_MA_HeLa_Br14_500ng_190618134442.raw -20190612_QX2_SeVW_MA_HeLa_500ng_LC05_CTCDoff_1.raw -20190612_QX3_JoMu_MA_HeLa_500ng_LC15_uPAC200cm.raw -20190613_QX0_MePh_MA_HeLa_500ng_LC07_1.raw -20190613_QX0_MePh_MA_HeLa_500ng_LC07_Stab_01.raw -20190613_QX0_MePh_MA_HeLa_500ng_LC07_Stab_02.raw -20190613_QX0_MePh_MA_HeLa_500ng_LC07_Stab_03.raw -20190613_QX4_JiYu_MA_HeLa_500ng.raw -20190614_QX2_SeVW_MA_HeLa_500ng_LC05_CTCDoff_1.raw -20190614_QX3_JoSw_MA_Hela_500ng_LC15.raw -20190614_QX3_JoSw_MA_Hela_500ng_LC15_190709210149.raw -20190615_QX4_JiYu_MA_HeLa_500ng.raw -20190617_QX4_JiYu_MA_HeLa_500ng.raw -20190617_QX8_IgPa_MA_HeLa_500ng.raw -20190618_QX3_LiSc_MA_Hela_500ng_LC15.raw -20190618_QX3_LiSc_MA_Hela_500ng_LC15_190619053902.raw -20190618_QX4_JiYu_MA_HeLa_500ng.raw -20190618_QX4_JiYu_MA_HeLa_500ng_190618125902.raw -20190618_QX4_JiYu_MA_HeLa_500ng_190618174520.raw -20190618_QX4_JiYu_MA_HeLa_500ng_190619010035.raw -20190618_QX4_JiYu_MA_HeLa_500ng_centroid.raw -20190619_QX7_IgPa_MA_HeLa_Br14_500ng.raw -20190619_QX7_IgPa_MA_HeLa_Br14_500ng_190619192949.raw -20190620_QX1_JoMu_MA_HeLa__500ng_LC10.raw -20190621_QX2_SeVW_MA_HeLa_500ng_LC05.raw -20190621_QX3_MePh_MA_Hela_500ng_LC15.raw -20190621_QX3_MePh_MA_Hela_500ng_LC15_190621150413.raw -20190621_QX4_JoMu_MA_HeLa_500ng.raw -20190621_QX4_JoMu_MA_HeLa_500ng_190621161214.raw -20190624_QX3_MaMu_MA_Hela_500ng_LC15.raw -20190624_QX4_JiYu_MA_HeLa_500ng.raw -20190625_QX0_MaPe_MA_HeLa_500ng_LC07_1.raw -20190625_QX7_IgPa_MA_HeLa_Br14_500ng.raw -20190626_QX1_JoMu_MA_HeLa_500ng_LC10.raw -20190626_QX1_JoMu_MA_HeLa_500ng_LC10_190626135146.raw -20190626_QX6_ChDe_MA_HeLa_500ng_LC09.raw -20190626_QX7_IgPa_MA_HeLa_Br14_500ng.raw -20190626_QX8_ChDe_MA_HeLa_BR14_500ng.raw -20190626_QX8_ChDe_MA_HeLa_BR14_500ng_190626194235.raw -20190627_QX0_AnBr_MA_HeLa_500ng_LC07_01.raw -20190627_QX3_MaMu_MA_Hela_500ng_LC15.raw -20190627_QX6_JoMu_MA_HeLa_500ng_LC09.raw -20190627_QX7_IgPa_MA_HeLa_Br14_500ng.raw -20190627_QX8_AnPi_MA_HeLa_BR14_500ng.raw -20190627_QX8_AnPi_MA_HeLa_BR14_500ng_190627185125.raw -20190628_QX0_AnBr_MA_HeLa_500ng_LC07_01.raw -20190628_QX0_AnBr_MA_HeLa_500ng_LC07_02.raw -20190628_QX6_AnPi_MA_HeLa_500ng_LC09.raw -20190629_QX4_JiYu_MA_HeLa_500ng_MAX_ALLOWED.raw -20190630_QX3_ChMa_MA_Hela_500ng_LC15.raw -20190701_QX2_LiSc_MA_HeLa_500ng_LC05.raw -20190701_QX2_LiSc_MA_HeLa_500ng_LC05_without_columnoven.raw -20190701_QX3_MiWi_MA_Hela_500ng_LC15.raw -20190701_QX4_MePh_MA_HeLa_500ng_MAX_ALLOWED.raw -20190701_QX6_MaTa_MA_HeLa_500ng_LC09.raw -20190701_QX8_AnPi_MA_HeLa_BR14_500ng.raw -20190702_QX0_AnBr_MA_HeLa_500ng_LC07_01.raw -20190702_QX0_AnBr_MA_HeLa_500ng_LC07_01_190702180001.raw -20190703_QX4_MaTa_MA_HeLa_500ng_MAX_ALLOWED.raw -20190703_QX7_AnPi_MA_HeLa_Br14_500ng.raw -20190704_QX6_MaTa_MA_HeLa_500ng_LC09.raw -20190705_QX0_AnBr_MA_HeLa_500ng_LC07_01.raw -20190705_QX0_AnBr_MA_HeLa_500ng_LC07_01_190707104639.raw -20190705_QX6_ChDe_MA_HeLa_500ng_LC09.raw -20190706_QX4_MiWi_MA_HeLa_500ng.raw -20190706_QX4_MiWi_MA_HeLa_500ng_190707003046.raw -20190707_QX3_MaTa_MA_Hela_500ng_LC15.raw -20190708_QX7_MaMu_MA_HeLa_Br14_500ng.raw -20190708_QX8_AnPi_MA_HeLa_BR14_500ng.raw -20190709_QX1_JoMu_MA_HeLa_500ng_LC10.raw -20190709_QX2_JoMu_MA_HeLa_500ng_LC05.raw -20190709_QX2_JoMu_MA_HeLa_500ng_LC05_190709143552.raw -20190709_QX3_MaTa_MA_Hela_500ng_LC15.raw -20190709_QX6_MaTa_MA_HeLa_500ng_LC09.raw -20190709_QX6_MaTa_MA_HeLa_500ng_LC09_20190709143044.raw -20190709_QX6_MaTa_MA_HeLa_500ng_LC09_20190709155356.raw -20190709_QX7_MaMu_MA_HeLa_Br14_500ng.raw -20190716_QX6_MaTa_MA_HeLa_500ng_LC09.raw -20190716_QX8_AnPi_MA_HeLa_BR14_500ng_190716192109.raw -20190717_QX2_IgPa_MA_HeLa_500ng_CTCDoff_LC05.raw -20190717_QX2_IgPa_MA_HeLa_500ng_CTCDoff_LC05_190719190656.raw -20190717_QX3_OzKa_MA_Hela_500ng_LC15.raw -20190717_QX3_OzKa_MA_Hela_500ng_LC15_190720214645.raw -20190717_QX3_OzKa_MA_Hela_500ng_LC15_190721144939.raw -20190717_QX8_ChSc_MA_HeLa_500ng.raw -20190718_QX6_MaTa_MA_HeLa_500ng_LC09.raw -20190718_QX8_ChSc_MA_HeLa_500ng.raw -20190719_QX1_JoMu_MA_HeLa_500ng_LC10.raw -20190719_QX8_ChSc_MA_HeLa_500ng.raw -20190721_QX0_MePh_MA_HeLa_500ng_LC07_01.raw -20190722_QX2_IgPa_MA_HeLa_500ng_CTCDoff_LC05.raw -20190722_QX3_MiWi_MA_Hela_500ng_LC15.raw -20190722_QX4_StEb_MA_HeLa_500ng.raw -20190722_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190722_QX8_ChSc_MA_HeLa_500ng.raw -20190722_QX8_ChSc_MA_HeLa_500ng_190722174431.raw -20190723_QX1_JoMu_MA_HeLa_500ng_LC10_pack-2000bar.raw -20190723_QX1_JoMu_MA_HeLa_500ng_LC10_pack-2000bar_2.raw -20190723_QX1_JoMu_MA_HeLa_500ng_LC10_pack-2000bar_3.raw -20190723_QX3_MiWi_MA_Hela_500ng_LC15.raw -20190723_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190724_QX0_MePh_MA_HeLa_500ng_LC07_01.raw -20190724_QX3_MiWi_MA_Hela_500ng_LC15.raw -20190724_QX7_AlRe_MA_HeLa_Br14_500ng.raw -20190725_QX0_MePh_MA_HeLa_500ng_LC07_01.raw -20190725_QX2_AnBr_MA_HeLa_500ng_CTCDoff_LC05.raw -20190725_QX2_MePh_MA_HeLa_500ng.raw -20190726_QX8_ChSc_MA_HeLa_500ng.raw -20190728_QX3_MiWi_MA_Hela_500ng_LC15.raw -20190729_QX0_AsJa_MA_HeLa_500ng_LC07_01.raw -20190729_QX2_IgPa_MA_HeLa_500ng_CTCDoff_LC05.raw -20190729_QX3_MiWi_MA_Hela_500ng_LC15.raw -20190729_QX4_PhGe_MA_Hela_500ng_LC15.raw -20190730_QX2_IgPa_MA_HeLa_500ng_CTCDoff_LC05.raw -20190730_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190731_QX1_LiSc_MA_HeLa_500ng_LC10.raw -20190731_QX2_IgPa_MA_HeLa_500ng_CTCDoff_LC05.raw -20190731_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190731_QX8_ChSc_MA_HeLa_500ng.raw -20190801_QX3_StEb_MA_Hela_500ng_LC15.raw -20190801_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190802_QX2_OzKa_MA_HeLa_500ng_CTCDoff_LC05.raw -20190802_QX2_OzKa_MA_HeLa_500ng_CTCDoff_LC05_190802231901.raw -20190802_QX6_MaTa_MA_HeLa_500ng_LC09.raw -20190802_QX6_MaTa_MA_HeLa_500ng_LC09_20190803134200.raw -20190802_QX6_MaTa_MA_HeLa_500ng_LC09_20190803182900.raw -20190802_QX7_AlRe_MA_HeLa_Br14_500ng.raw -20190803_QX8_AnPi_MA_HeLa_BR14_500ng.raw -20190804_QX0_AsJa_MA_HeLa_500ng_LC07_01.raw -20190804_QX3_StEb_MA_Hela_500ng_LC15.raw -20190805_QX0_FyHa_MA_HeLa_500ng_LC07_01.raw -20190805_QX1_LiSc_MA_HeLa_500ng_LC10.raw -20190805_QX2_OzKa_MA_HeLa_500ng_CTCDoff_LC05.raw -20190805_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20190805_QX7_AlRe_MA_HeLa_Br14_500ng.raw -20190805_QX7_AlRe_MA_HeLa_Br14_500ng_190806072128.raw -20190805_QX8_AnPi_MA_HeLa_BR14_500ng.raw -20190806_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20190806_QX3_FyHa_MA_Hela_500ng_LC15.raw -20190806_QX3_StEb_MA_Hela_500ng_LC15.raw -20190806_QX4_StEb_MA_HeLa_500ng.raw -20190806_QX6_MaTa_MA_HeLa_500ng_LC09.raw -20190806_QX6_MaTa_MA_HeLa_500ng_LC09_20190806172817.raw -20190806_QX8_AnPi_MA_HeLa_BR14_500ng.raw -20190808_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190809_QX0_FyHa_MA_HeLa_500ng_LC07_01.raw -20190809_QX7_AlRe_MA_HeLa_Br14_500ng.raw -20190809_QX7_AlRe_MA_HeLa_Br14_500ng_190813124558.raw -20190809_QX8_MiWi_MA_HeLa_BR14_500ng.raw -20190811_QX0_AnBr_MA_HeLa_500ng_LC07_01.raw -20190812_QX4_PhGe_MA_Hela_500ng_LC1.raw -20190812_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190813_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20190813_QX3_LiSc_MA_Hela_500ng_LC15.raw -20190813_QX4_StEb_MA_HeLa_500ng.raw -20190813_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190814_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190814_QX6_AsJa_MA_HeLa_500ng_LC09_20190814155852.raw -20190814_QX8_JaBa_MA_HeLa_BR14_500ng.raw -20190814_QX8_JaBa_MA_HeLa_BR14_500ng_190818004141.raw -20190814_QX8_JaBa_MA_HeLa_BR14_500ng_190819030435.raw -20190815_QX0_AnBr_MA_HeLa_500ng_LC07_01.raw -20190816_QX0_AnBr_MA_HeLa_500ng_LC07_01.raw -20190816_QX0_AnBr_MA_HeLa_500ng_LC07_01_190820113117.raw -20190816_QX0_AnBr_MA_HeLa_500ng_LC07_02.raw -20190816_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20190816_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190816_QX7_AnBr_MA_HeLa_Br14_500ng_01.raw -20190816_QX7_AnBr_MA_HeLa_Br14_500ng_02.raw -20190816_QX7_AnBr_MA_HeLa_Br14_500ng_02_190827114153.raw -20190817_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190818_QX0_AnBr_MA_HeLa_500ng_LC07_CTCD_OFF_01.raw -20190818_QX0_AnBr_MA_HeLa_500ng_LC07_CTCD_OFF_02.raw -20190818_QX0_AnBr_MA_HeLa_500ng_LC07_Standard_01.raw -20190818_QX0_AnBr_MA_HeLa_500ng_LC07_Standard_02.raw -20190818_QX7_AnBr_MA_HeLa_Br14_500ng_01.raw -20190819_QX1_LiSc_MA_HeLa_500ng_LC10.raw -20190819_QX1_LiSc_MA_HeLa_500ng_LC10_2.raw -20190819_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20190819_QX3_LiSc_MA_Hela_500ng_LC15.raw -20190819_QX4_StEb_MA_HeLa_500ng.raw -20190819_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190819_QX7_AnBr_MA_HeLa_Br14_500ng_01.raw -20190819_QX8_JaBa_MA_HeLa_BR14_500ng.raw -20190820_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC10.raw -20190820_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC10_190820172227.raw -20190820_QX7_AnBr_MA_HeLa_Br14_500ng_01.raw -20190821_QX0_AnBr_MA_HeLa_500ng_LC07_01.raw -20190821_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190822_QX0_AnBr_MA_HeLa_500ng_LC07_01.raw -20190822_QX0_AnBr_MA_HeLa_500ng_LC07_02.raw -20190822_QX0_AnBr_MA_HeLa_500ng_LC07_03.raw -20190822_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC10.raw -20190822_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190823_QX0_AnBr_MA_HeLa_500ng_LC07_01.raw -20190823_QX0_AnBr_MA_HeLa_500ng_LC07_01_190824152456.raw -20190823_QX0_AnBr_MA_HeLa_500ng_LC07_01_190825070959.raw -20190823_QX0_AnBr_MA_HeLa_500ng_LC07_01_190825211633.raw -20190823_QX0_AnBr_MA_HeLa_500ng_LC07_1preDischarge.raw -20190823_QX4_LiSc_MA_HeLa_500ng.raw -20190823_QX7_AnBr_MA_HeLa_Br14_500ng_01.raw -20190825_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190826_QX0_ChDe_MA_HeLa_500ng_LC07_01.raw -20190826_QX0_ChDe_MA_HeLa_500ng_LC07_03.raw -20190826_QX0_ChDe_MA_HeLa_500ng_LC07_05.raw -20190826_QX1_LiSc_MA_HeLa_500ng_LC10.raw -20190826_QX1_LiSc_MA_HeLa_500ng_LC10_190827011213.raw -20190826_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190826_QX7_AnBr_MA_HeLa_Br14_500ng_01.raw -20190826_QX7_AnBr_MA_HeLa_Br14_500ng_01_190827114215.raw -20190826_QX8_JaBa_MA_HeLa_BR14_500ng.raw -20190827_QX0_ChDe_MA_HeLa_500ng_LC07_01.raw -20190827_QX0_ChDe_MA_HeLa_500ng_LC07_02.raw -20190827_QX0_ChDe_MA_HeLa_500ng_LC07_03.raw -20190827_QX0_ChDe_MA_HeLa_500ng_LC07_04.raw -20190827_QX0_ChDe_MA_HeLa_500ng_LC07_05.raw -20190827_QX0_ChDe_MA_HeLa_500ng_LC07_06.raw -20190827_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC10.raw -20190827_QX3_LiSc_MA_Hela_500ng_LC15.raw -20190827_QX3_LiSc_MA_Hela_500ng_LC15_190828161744.raw -20190827_QX7_AnBr_MA_HeLa_Br14_500ng_01.raw -20190828_QX1_LiSc_MA_HeLa_500ng_LC10.raw -20190828_QX8_AlRe_MA_HeLa_BR14_500ng.raw -20190829_QX4_LiSc_MA_HeLa_500ng.raw -20190830_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190902_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20190902_QX3_ChDe_MA_Hela_500ng_LC15.raw -20190902_QX4_JiYu_MA_HeLa_500ng.raw -20190902_QX4_JiYu_MA_HeLa_500ng_190902201537.raw -20190902_QX4_JiYu_MA_HeLa_500ng_190902223701.raw -20190903_QX0_OzKa_MA_HeLa_500ng_LC07_01.raw -20190903_QX0_OzKa_MA_HeLa_500ng_LC07_01_190904145103.raw -20190903_QX6_AsJa_MA_HeLa_500ng_LC09.raw -20190903_QX7_AnBr_MA_HeLa_Br14_500ng_01.raw -20190903_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20190904_QX6_ChDe_MA_HeLa_500ng_LC09.raw -20190904_QX7_AlRe_MA_HeLa_Br14_500ng_01.raw -20190904_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20190905_QX4_JiYu_MA_HeLa_500ng.raw -20190906_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20190906_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05_190906190218.raw -20190909_QX0_OzKa_MA_HeLa_500ng_LC07_01.raw -20190909_QX3_ChDe_MA_Hela_500ng_LC15.raw -20190909_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20190909_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20190909_QX8_JuSc_MA_HeLa_BR14_500ng_190909141252.raw -20190910_QX1_LiSc_MA_HeLa_500ng_LC10_2.raw -20190910_QX4_JoSw_MA_HeLa_500ng.raw -20190911_QX0_ChDe_MA_HeLa_500ng_LC07_01.raw -20190911_QX6_ChDe_MA_HeLa_500ng_LC09.raw -20190911_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20190911_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20190912_QX1_LiSc_MA_HeLa_500ng_LC10_2.raw -20190912_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20190912_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20190912_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20190912_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20190913_QX0_ChDe_MA_HeLa_500ng_LC07_05.raw -20190913_QX0_ChDe_MA_HeLa_500ng_LC07_07_CTCD_off.raw -20190913_QX0_ChDe_MA_HeLa_500ng_LC07_09.raw -20190913_QX0_ChDe_MA_HeLa_500ng_LC12_01.raw -20190913_QX0_ChDe_MA_HeLa_500ng_LC12_01_190913181030.raw -20190913_QX0_ChDe_MA_HeLa_500ng_LC12_03.raw -20190913_QX0_ChDe_MA_HeLa_500ng_LC12_03_190913230336.raw -20190913_QX4_MiWi_MA_HeLa_500ng.raw -20190913_QX6_ChDe_MA_HeLa_500ng_LC09.raw -20190913_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20190913_QX7_ChDe_MA_HeLa_Br14_500ng_190924060155.raw -20190914_QX3_ChDe_MA_Hela_500ng_LC15.raw -20190914_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20190916_QX3_LiSc_MA_Hela_500ng_LC15.raw -20190916_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20190916_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20190917_QX0_ChDe_MA_HeLa_500ng_LC12_01.raw -20190917_QX3_LiSc_MA_Hela_500ng_LC15.raw -20190917_QX4_StEb_MA_HeLa_500ng.raw -20190918_QX0_ChDe_MA_HeLa_500ng_LC12_01.raw -20190918_QX0_ChDe_MA_HeLa_500ng_LC12_01_190918155119.raw -20190918_QX0_ChDe_MA_HeLa_500ng_LC12_03.raw -20190918_QX0_ChDe_MA_HeLa_500ng_LC12_05.raw -20190918_QX0_ChDe_MA_HeLa_500ng_LC12_07.raw -20190918_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20190918_QX3_OzKa_MA_Hela_500ng_LC15.raw -20190918_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20190918_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20190919_QX1_LiSc_MA_HeLa_75umID_15cm_500ng_LC10_1.raw -20190919_QX1_LiSc_MA_HeLa_75umID_15cm_500ng_LC10_1_191007121002.raw -20190919_QX1_LiSc_MA_HeLa_75umID_15cm_500ng_LC10_2.raw -20190919_QX1_LiSc_MA_HeLa_75umID_15cm_500ng_LC10_3.raw -20190919_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20190919_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20190919_QX6_JuSc_MA_HeLa_500ng_LC09_20190919173318.raw -20190920_QX3_ADB_MA_HeLa_500ng_DDA.raw -20190920_QX4_StEb_MA_HeLa_500ng.raw -20190920_QX4_StEb_MA_HeLa_500ng_190921074136.raw -20190922_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20190923_QX2_ADB_MA_HeLa_500ng_CTCDoff_LC05_01.raw -20190923_QX2_ADB_MA_HeLa_500ng_CTCDoff_LC05_02.raw -20190923_QX2_ADB_MA_HeLa_500ng_CTCDoff_LC05_02_191015194030.raw -20190923_QX3_MiWi_MA_Hela_500ng_LC15.raw -20190923_QX4_StEb_MA_HeLa_500ng.raw -20190923_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20190924_QX0_AsJa_MA_HeLa_500ng_LC12_01.raw -20190924_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20190925_QX2_ADB_MA_HeLa_500ng_CTCDoff_LC05.raw -20190925_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20190925_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20190925_QX6_JuSc_MA_HeLa_500ng_LC09_20190926214110.raw -20190925_QX6_JuSc_MA_HeLa_500ng_LC09_20190929121636.raw -20190926_QX4_StEb_MA_HeLa_500ng.raw -20190927_QX2_FlMe_MA_HeLa_500ng_CTCDoff_LC05_01.raw -20190927_QX2_FlMe_MA_HeLa_500ng_CTCDoff_LC05_02.raw -20190927_QX3_MiWi_MA_Hela_500ng_LC15.raw -20190927_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20190929_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20190930_QX0_AsJa_MA_HeLa_500ng_LC12_01.raw -20190930_QX3_MiWi_MA_Hela_500ng_LC15.raw -20190930_QX4_MePh_MA_HeLa_500ng.raw -20191001_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20191001_QX7_IgPa_MA_HeLa_500ng_LC12_13.raw -20191001_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20191002_QX4_MePh_MA_HeLa_500ng.raw -20191003_QX3_MiWi_MA_Hela_500ng_LC15.raw -20191004_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20191007_QX1_JoMu_MA_HeLa_500ng_LC10.raw -20191007_QX2_LiSc_MA_HeLa_500ng_CTCDoff_LC05.raw -20191007_QX3_LiSc_MA_Hela_500ng_LC15.raw -20191007_QX3_LiSc_MA_Hela_500ng_LC15_191008004308.raw -20191007_QX3_LiSc_MA_Hela_500ng_LC15_191014174622.raw -20191007_QX4_JoSw_MA_HeLa_500ng.raw -20191007_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20191007_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20191007_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20191008_QX0_AsJa_MA_HeLa_500ng_LC12_01.raw -20191008_QX0_AsJa_MA_HeLa_500ng_LC12_01_191008164424.raw -20191008_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20191009_QX2_SeVW_MA_HeLa_500ng_CTCDoff_LC05.raw -20191009_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20191010_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20191011_QX0_ChDe_MA_HeLa_500ng_LC12_01.raw -20191011_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20191014_QX0_AsJa_MA_HeLa_500ng_LC12_01.raw -20191014_QX1_JoMu_MA_HeLa_500ng_LC10.raw -20191014_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20191014_QX6_JuSc_MA_HeLa_500ng_LC09_20191014160507.raw -20191014_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20191015_QX3_AlRe_MA_Hela_500ng_LC15.raw -20191015_QX4_JiYu_MA_HeLa_500ng_MAX_ALLOWED.raw -20191015_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20191015_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20191016_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20191017_QX1_teph_MA_HeLa_500ng_LC10.raw -20191017_QX1_teph_MA_HeLa_500ng_LC10_2.raw -20191017_QX2_ADB_MA_HeLa_500ng_CTCDoff_LC05.raw -20191019_QX8_JuSc_MA_HeLa_BR14_500ng.raw -20191020_QX2_ADB_MA_HeLa_500ng_CTCDoff_LC05.raw -20191021_QX3_AlRe_MA_Hela_500ng_LC15.raw -20191021_QX3_AlRe_MA_Hela_500ng_LC15_191023200659.raw -20191021_QX4_JoSw_MA_HeLa_500ng.raw -20191021_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20191021_QX8_AlDa_MA_HeLa_BR14_500ng.raw -20191022_QX0_AsJa_MA_HeLa_500ng_LC12_01.raw -20191022_QX4_StEb_MA_HeLa_500ng.raw -20191022_QX7_ChDe_MA_HeLa_Br14_500ng.raw -20191023_QX0_AsJa_MA_HeLa_500ng_LC12_01.raw -20191023_QX2_ADB_MA_HeLa_500ng_CTCDoff_LC05.raw -20191024_QX1_JoMu_MA_HeLa_500ng_LC10_2.raw -20191025_QX0_AsJa_MA_HeLa_500ng_LC12_01.raw -20191025_QX0_AsJa_MA_HeLa_500ng_LC12_03.raw -20191025_QX0_AsJa_MA_HeLa_500ng_LC12_05.raw -20191025_QX6_JuSc_MA_HeLa_500ng_LC09.raw -20191028_QX3_LiSc_MA_Hela_500ng_LC15_1.raw -20191028_QX3_LiSc_MA_Hela_500ng_LC15_1_191029014900.raw -20191028_QX3_LiSc_MA_Hela_500ng_LC15_1_191029100827.raw -20191028_QX3_LiSc_MA_Hela_500ng_LC15_1_191029124318.raw -20191028_QX3_LiSc_MA_Hela_500ng_LC15_2.raw -20191028_QX3_LiSc_MA_Hela_500ng_LC15_2_191029042255.raw -20191028_QX4_StEb_MA_HeLa_500ng.raw -20191028_QX4_StEb_MA_HeLa_500ng_191029155608.raw -20191029_QX8_JuSc_MA_HeLa_BR14_500ng.raw \ No newline at end of file diff --git a/workflows/maxquant/README.md b/workflows/maxquant/README.md deleted file mode 100644 index e8cf9a4ff..000000000 --- a/workflows/maxquant/README.md +++ /dev/null @@ -1,218 +0,0 @@ -# MaxQuant Workflow - -## Setup on CR2 -If you already have a working version of snakemake, consider to skip this: -``` -module load tools -module load anaconda3/2019.10 -conda init bash -bash -conda env create -f vaep/workflows/maxquant/environment.yml -# ~/.conda/envs/snakemake -conda activate snakemake -# untrack changes to config -git update-index --assume-unchanged workflows/maxquant/config.yaml -``` - -## Example `config.yaml` for Workflow -Here the username is `henweb` and the group is Simon Rasmussen's group `cpr_10006`. - -``` -DATADIR: /home/projects/cpr_10006/people/henweb/hela/ -SCRIPTDIR: /home/projects/cpr_10006/people/henweb/vaep/workflows/maxquant/ - -#Either your own or (see below) -MAXQUANTEXE: /home/projects/cpr_10006/people/henweb/MaxQuant_1.6.12.0/MaxQuant/bin/MaxQuantCmd.exe -# MAXQUANTEXE: /services/tools/maxquant/1.6.7.0/MaxQuant.exe - -MQ_PAR_TEMP: /home/projects/cpr_10006/people/henweb/vaep/workflows/maxquant/mqpar_template_1.6.xml -THREATS_MQ: 8 - -REMOTE_OUT: io.erda.dk -REMOTE_FOLDER: mq_out - -# Remote name for fetching files and list of all files -REMOTE_IN: hela -FILES: ../hela_files.txt -FILES_EXCLUDED: log_excluded_files.txt -FILES_FAILED: log_failed.txt -``` - -> You have to specify the fasta file paths manually in the parameter template file -> referenced in MQ_PAR_TEMP, e.g. `/home/projects/cpr_10006/people/henweb/fasta/myfasta.fasta` - -If you specify passwords in your config file you might want to restrict permissions to your user - -``` -chmod 600 config.yaml -``` - -### Find MaxQuant exectuable -You can either use a pre-exisiting MaxQuant installation or a new one. -Once you know the path, you do not need to load the module explicitly -into your set of environment variables. -``` -module load mono/5.20.1.19 maxquant/1.6.7.0 -export | grep MAXQUANT # find path to MaxQuant executable -``` - -> It seems that also on minor version updates the parameter file of MaxQuant is -> not preserved. Make sure that your template parameter file is working together -> with your MaxQuant version - -## Test your Workflow - Dry-Run of Snakemake - -Make sure to be in the MaxQuant workflow folder `workflows/maxquant/` and -have a session which you can reconnect to (using e.g. `screen` or `tmux`). - -### Set `SSHPASS` -This workflow uses in the current implementation a password protected sftp -connection. In order to login your local environment in which you run -snakemake has to have a password, `` set. - -```bash -export SSHPASS= -``` - -If you don't, snakemake will remind you. -Howwever, snakemake cannot check if the password is correct -before execution, so best verify yourself that it works in the shell you execute. -The `REMOTE` is the same you specified in the `config.yml`: - -```bash -sshpass -e sftp -B 258048 REMOTE <<< "pwd" -``` - -If you set up a SSH connection for your `REMOTE_IN`, you can just set `SSHPASS` to -anything or comment the two line in the `Snakefile`. - -### Dry-RUN - -``` -snakemake -n -snakemake -n --report -``` - -### Run locally - -Either on your computer or in an interactive shell (`iqsub`) - -Running snakemake with many repeated sample which might fail, you can type: -``` -snakemake -k -``` - -### Run on cluster - -#### Using a separate script - -``` -qsub -V run_sm_on_cluster.sh -``` - -The `-V` options passes the current environment variables to the shell started by the -run, see [here](http://docs.adaptivecomputing.com/torque/4-0-2/Content/topics/commands/qsub.htm) - -The script itself contains the cluster execution. Please change the number of parallel jobs -in `run_sm_on_cluster.sh`: - -```bash -snakemake --jobs 6 -k --latency-wait 30 --use-envmodules \ ---cluster "qsub -l walltime={resources.walltime},nodes=1:ppn={threads},mem={resources.mem_mb}mb"\ -" -W group_list=cpr_10006 -A cpr_10006 -m f -V "\ -"-e {params.logdir} -o {params.logdir}" -n -``` - -> Once you are sure, remove the dryrun flag `-n`. Dry runs do not necessarily have to be -> sent to the queue. - -Alternatively invoked a profile defined from a [template](https://github.com/Snakemake-Profiles/pbs-torque). - -Using the profile, the configuration -defined in `config.yaml` and in the `Snakefile` will be used. - -``` -snakemake --profile pbs-torque --jobs 10 --latency-wait 10 -k -``` - -#### Logs - -All files resulting from executions are stored under the `.snakemake`. See the last file -in the `.snakemake/log` folder for inspecting the process of the currently executed -snakemake job. - - -## After running snakemake - -> The file names can be changed in the `config.yaml` - -After snakemake execution of the files in `[hela_files.txt](../hela_files.txt) -you should find new files in the workflow folder [maxquant](vaep/workflows/maxquant): - -``` -log_completed.txt -log_excluded_files.txt -log_failed.txt -sftp_commands -``` - -The `log_excluded_files.txt` will be discarded in further workflow runs -(due to being too small) and `log_failed.txt` holds -files which failed although their size is sufficient. The ladder are not automatically -excluded when you re-run snakemake, as the reason for the failure might be on the -server side. - -The `sftp_commands` file is the set of commands for batch-mode execution for -transferring files to erda.dk. Assuming the server was reachable when executing the -job, the files should have been transferred during the run. Otherwise you can re-run -the transfer again: - -If you set up access to your erda folder appropriatly -you should be able to connect to `erda `. I named it `erda io.erda.dk`. -If you can connect using this command, execute the sftp command in batch mode providing -`sftp_commands` as an argument in order to store the files in a `hela` folder on your -erda root directory. - -``` -sftp -B 258048 -b sftp_commands io.erda.dk -``` - -> afterwards one should rename the sftp_commands file or move it to an archive folder. - -## Find output files -> Look up only for now -Find MQ output files in `hela` folder and remove them by age: -``` -find ./hela/ -name '*txt*' -type d -print -find ./hela/ -path ./*/combined/txt -type d -ls ./hela/ -ltr # check for old files -find ./hela/ -mtime +2 -#find ./hela/ -mtime +2 -exec rm {} \; -#find ./hela/ -mtime +2 -exec rmdir {} \; -type d -#find ./hela/ -type d -empty -delete -#find ./hela/ -mtime +2 -exec rm -r {} \; -``` - -## Check files on server - -In order to see if a corresponding folder on exists on `erda.dk`, you can get a dump of the -files in the output folder. First get a list of all files in the `mq_out` folder on erda -(the default folder for storing results, but choose what is in `config.yaml`) : - -``` -sftp -q io.erda.dk:mq_out/ <<< "ls" | grep -v '^sftp>' > hela_processed.txt -``` - -> this could be integrated into snakemake _target_ rule. - -The `hela_processed.txt` is then the input of the small script `check_current_files.py`: - -``` -python check_current_files.py -f ../hela_processed.txt -v -``` - -which dumps the missing, not excluded or failed files into `current_files_to_do.txt`. -This comparison only checks it the folder for a file exists on the REMOTE if it should be -completed. `current_files_to_do.txt` can then itself be a new input file or used to remove -some output files. If you are sure set the `forceall` option in snakemake, -e.g. in `run_sm_on_cluster.sh`. diff --git a/workflows/maxquant/Snakefile b/workflows/maxquant/Snakefile deleted file mode 100644 index af23feed7..000000000 --- a/workflows/maxquant/Snakefile +++ /dev/null @@ -1,194 +0,0 @@ -""" -Incremental development: - -1) run on local machine in dry-run (iteratively adding functionality) -2) execute using `qsub` (or interactive shell on CR2) -3) add queuing system `qsub` -""" -import os -from pathlib import Path -configfile: 'config.yaml' # access using config['key'] -MIN_FILE_SIZE = 900_000_000 - -folder_logs = Path(config['LOGDIR']) -results_foldername = os.path.basename(config["RESULTSDIR"]) - -# only needed if login to remote is not set up using ssh keys -# move away from config into envvars -# envvars: -# "SSHPASS" - -# wildcard_mqpar = os.path.join(config['SCRIPTDIR'], 'mqpar_xmls', "mqpar_{file}.xml") -# mq_par_temp = os.path.join(config['SCRIPTDIR'], config['MQ_PAR_TEMP']) - -print(f"Use files from: {config['FILES']}") -with open(config['FILES'], encoding='utf-8') as f: - FILES = set(line.strip().split('.raw')[0] for line in f) - -# Order Files (set gives an unordered) -FILES = list(FILES) -FILES.sort() # otherwise execution order is not deterministic due to set -# local, excluded files previously identified as to small -fname_excluded = folder_logs / \ - f"{results_foldername}_excluded_files.txt" -print(f"Exclude files from: {fname_excluded}") -try: - with open(fname_excluded, encoding='utf-8') as f: - FILES_EXCLUDED = set(line.strip().split('.raw')[0] for line in f) -except FileNotFoundError: - print(f"No such file: {fname_excluded} - Creating one.") - with open(fname_excluded, 'w'): - pass - FILES_EXCLUDED = [] -for _file_to_remove in FILES_EXCLUDED: - try: - FILES.remove(_file_to_remove) - except ValueError as e: - print(f"WARNING: File to exclude not in inputs: {_file_to_remove}") - - -# local rules are excuted in the process (job) running snakemake -# allows for ssh-multiplexing, see https://blog.scottlowe.org/2015/12/11/using-ssh-multiplexing/ -localrules: target, mqpar, download_file, upload_file - - -# Thinnode resources sharing: 40 cores and 196 GB RAM (minus 2GB for snakemake) -# http://www.dewassoc.com/kbase/hard_drives/binary_v_decimal_measurement.htm -job_ram_mb = int(204_800 / 40 * config['THREATS_MQ']) - -# #Target Rule: -rule target: - input: - # mockfile approach: https://stackoverflow.com/a/53751654/9684872 - # replace? https://snakemake.readthedocs.io/en/stable/snakefiles/rules.html#directories-as-outputs - expand(os.path.join(config['RESULTSDIR'], - "{file}", "{file}.txt"), file=FILES) - -# File size could be done on remote before downloading, only security check afterwards?s -rule download_file: - output: - raw = temp(os.path.join(config['DATADIR'], "{file}", "{file}.raw")) - benchmark: - os.path.join(config['RESULTSDIR'], "{file}", "benchmark_download.tsv") - params: - file = "{file}.raw", - logdir = os.path.join(config['RESULTSDIR'], "{file}"), - remote = config['REMOTE_IN'], # SSHPASS migt be used here - datadir = os.path.join(config['DATADIR'], "{file}"), - min_file_size = MIN_FILE_SIZE - resources: - walltime = 300, nodes = 1, mem_mb = 2048 - threads: - 1 - shell: - """ - sftp -B 258048 {params.remote} <<< 'get {params.file} {output.raw}' && ( - FILESIZE=$(stat -c%s {output.raw}) && - [ $FILESIZE -le {params.min_file_size} ] && - echo '{params.file}' >> {fname_excluded} && - echo "{params.file} is too small: $FILESIZE" && - echo "File is too small: $FILESIZE" > {params.logdir}/download_too_small.log && - rm -R {params.datadir} && - exit 1 || exit 0 ) - """ - -# Is it possible to have relative paths for the Output? -# Path('mqpar_xmls') / 'mq_par_{file}.xml' -# -# should it be a temporary file, otherwise THREADS_MQ is fixed? -rule mqpar: - benchmark: - Path(config['RESULTSDIR']) / "{file}" / "benchmark_mqpar.tsv" - params: - raw = os.path.join(config['DATADIR'], "{file}", "{file}.raw"), - mq_par_temp = os.path.join(config['SCRIPTDIR'], config['MQ_PAR_TEMP']), - threads_mq = config['THREATS_MQ'], - logdir = os.path.join(config['RESULTSDIR'], "{file}"), - resources: - walltime = 240, nodes = 1, mem_mb = 1024 - threads: - 1 - output: - mq_par = Path(config['SCRIPTDIR']) / 'mqpar_xmls' / "mqpar_{file}.xml" - run: - # snakemake create folders itself if missing -> download job into folder - # - # multi-line with statements natively supported from Python 3.9: - # https://stackoverflow.com/questions/31039022/python-multi-line-with-statement - with open(file=params.mq_par_temp, encoding='utf-8') as infile, open(file=output.mq_par, mode='w', encoding='utf-8') as outfile: - for line in infile: - line = line.replace('PATH', params.raw) - line = line.replace('NUM_THREADS', str(params.threads_mq)) - outfile.write(line) - outfile.close() - infile.close() - - -rule maxquant: - input: - raw = os.path.join(config['DATADIR'], "{file}", "{file}.raw"), - mq_par = os.path.join(config['SCRIPTDIR'], - 'mqpar_xmls', "mqpar_{file}.xml"), - exe = config['MAXQUANTEXE'] - benchmark: - os.path.join(config['RESULTSDIR'], "{file}", "benchmark_MQ.tsv") - output: - out = os.path.join(config['RESULTSDIR'], - "{file}", "{file}_mq_done.txt") - resources: - mem_mb = job_ram_mb, nodes = 1, walltime = '5:00:00' - threads: - config['THREATS_MQ'] - envmodules: - "tools", - "mono/5.20.1.19" - params: - datadir = os.path.join(config['DATADIR'], "{file}"), - logdir = os.path.join(config['RESULTSDIR'], "{file}"), - log_failed = f"{results_foldername}_failed.txt", - log_completed = folder_logs / f"{results_foldername}_completed.txt", - remote = config['REMOTE_OUT'], - min_file_size = MIN_FILE_SIZE - shell: - # https://snakemake.readthedocs.io/en/stable/project_info/faq.html#i-don-t-want-snakemake-to-detect-an-error-if-my-shell-command-exits-with-an-exitcode-1-what-can-i-do - # write shell script? - # https: // stackoverflow.com/a/27301889/9684872 - # changing in presence of here-documents (<< EOF EOF below) - # https://snakemake.readthedocs.io/en/stable/project_info/faq.html#is-it-possible-to-pass-variable-values-to-the-workflow-via-the-command-line - # { have to be escaped as {{ - """ - mono --version && - FILESIZE=$(stat -c%s {input.raw}) && - [ $FILESIZE -ge {params.min_file_size} ] && - mono {input.exe} {input.mq_par} && - echo "$(date +"%F %T"): Finished run with MaxQuant version {input.exe}" >> {output.out} && - echo '-mkdir mq_out/{wildcards.file}' >> sftp_commands && - echo '-put {params.datadir}/combined/txt/* mq_out/{wildcards.file}' >> sftp_commands && - cp {input.mq_par} {params.datadir}/combined/txt/mqpar.xml && - echo '{wildcards.file}' >> {params.log_completed} || - ( echo '{wildcards.file}' >> {params.log_failed} && - echo "Size of {input.raw}: $FILESIZE" && - rm -R {params.datadir} && - exit 1 ) - """ - -rule upload_file: - input: - mq_done = os.path.join( - config['RESULTSDIR'], "{file}", "{file}_mq_done.txt") - output: - out = os.path.join(config['RESULTSDIR'], - "{file}", "{file}.txt") - resources: - mem_mb = job_ram_mb, nodes = 1, walltime = 900 - params: - datadir = os.path.join(config['DATADIR'], "{file}"), - remote = config['REMOTE_OUT'] - shell: - """ - sftp -B 258048 {params.remote} <<< '-mkdir mq_out/{wildcards.file}\nput {params.datadir}/combined/txt/* mq_out/{wildcards.file}' && - rm -R {params.datadir} && - echo 'Done uploading to mq_out/{wildcards.file} on {params.remote}' && - echo "$(date +"%F %T"): Finished upload to erda." >> {output.out} || - echo 'Failed upload for {wildcards.file}' - """ diff --git a/workflows/maxquant/bin/check_current_files.py b/workflows/maxquant/bin/check_current_files.py deleted file mode 100644 index c7a70dc35..000000000 --- a/workflows/maxquant/bin/check_current_files.py +++ /dev/null @@ -1,64 +0,0 @@ -''' -Create a diff view between files on server and files which should be completed. -The comparison is only based on folders. - -## hints -- reads config.yaml -- compare files on erda.io.dk with FILES -- exclude failed and excluded files -- outputs a file with diffs. -''' -import argparse -import yaml - -__author__ = 'Henry Webel' - -parser = argparse.ArgumentParser( - prog='FileCheckOnErda', - description='Check if current set of files which did not fail are uploaded to erda. ' - 'Does not check for empty folders.') - -parser.add_argument('-f', '--files_on_erda', - help='List of folders on erda.', required=True) -parser.add_argument('-v', '--verbose', help='Prinbt additional information', - action='count') -parser.add_argument('-o', '--outfile', default='current_files_to_do.txt') - -args = parser.parse_args() - -with open('config.yaml') as f: - config = yaml.safe_load(f) - -if args.verbose: - print(f"Load file: {config['FILES']}") - -with open(config['FILES'], encoding='utf-8') as f: - FILES = set(line.strip().split('.raw')[0] for line in f) - -if args.verbose: - print(f"Load file: {config['FILES_EXCLUDED']}") - -with open(config['FILES_EXCLUDED'], encoding='utf-8') as f: - FILES_EXCLUDED = set(line.strip().split('.raw')[0] for line in f) - -if args.verbose: - print(f"Load file: {config['FILES_FAILED']}") - -with open(config['FILES_FAILED'], encoding='utf-8') as f: - FILES_FAILED = set(line.strip().split('.raw')[0] for line in f) - -with open(args.files_on_erda, encoding='utf-8') as f: - # although no `.raw` ending, keep the default loading syntax - FILES_ON_ERDA = set(line.strip().split('.raw')[0] for line in f) - -files_to_do = FILES - FILES_EXCLUDED - FILES_FAILED - FILES_ON_ERDA -files_to_do = [f"{file}.raw" for file in files_to_do] - -if args.verbose: - print(f"In total {len(files_to_do)} are not processed:\n\t", - "\n\t".join(file for file in files_to_do)) - -with open(args.outfile, mode='w') as f: - f.writelines('\n'.join(file for file in files_to_do)) - -print(f'Saved difference between server and completed files: {args.outfile}') diff --git a/workflows/maxquant/bin/remove_duplicates.py b/workflows/maxquant/bin/remove_duplicates.py deleted file mode 100644 index 7fc0da2ea..000000000 --- a/workflows/maxquant/bin/remove_duplicates.py +++ /dev/null @@ -1,44 +0,0 @@ -''' -Create a copy of a file with duplicates removed. - -## hints -- exclude failed and excluded files -''' -import argparse -from pathlib import Path - -__author__ = 'Henry Webel' - -parser = argparse.ArgumentParser( - prog='Remove duplicate lines in file', - description='Remove duplicated lines and save a copy.') - -parser.add_argument('-f', '--file', - help='File with duplicates', required=True) -parser.add_argument('-v', '--verbose', help='Prinbt additional information', - action='count') -parser.add_argument('-o', '--outfile', required=False) - - -args = parser.parse_args() - -file = Path(args.file) - -try: - unique = set() - with open(file) as f: - for line in f: - unique.update((line.strip(),)) - unique = list(unique) - unique.sort() -except FileNotFoundError: - raise FileNotFoundError(f"No such file: {file} relative to {file.cwd()}.") - -out_file = args.outfile - -if not out_file: - out_file = file.parent / f"{file.stem}_wo_duplicates{file.suffix}" - -with open(out_file, 'w') as f: - f.writelines([f'{line}\n' for line in unique]) - diff --git a/workflows/maxquant/computerome2.yaml b/workflows/maxquant/computerome2.yaml deleted file mode 100644 index b44b8a0e7..000000000 --- a/workflows/maxquant/computerome2.yaml +++ /dev/null @@ -1,2 +0,0 @@ -cluster: qsub -jobs: 20 diff --git a/workflows/maxquant/config.yaml b/workflows/maxquant/config.yaml deleted file mode 100644 index 69e06afa9..000000000 --- a/workflows/maxquant/config.yaml +++ /dev/null @@ -1,5 +0,0 @@ -DATADIR: path/to/specify -SCRIPTDIR: path/to/specify -MAXQUANTEXE: path/to/specify -MQ_PAR_TEMP: path/to/specify -THREATS_MQ: 8 \ No newline at end of file diff --git a/workflows/maxquant/environment.yml b/workflows/maxquant/environment.yml deleted file mode 100644 index b6db284ea..000000000 --- a/workflows/maxquant/environment.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: snakemake -channels: - - conda-forge - - bioconda - - defaults -dependencies: - - snakemake=5.19.3 - - pygraphviz - #- cookiecutter -# #set individual environment location -# prefix: /home/.conda/envs/snakemake diff --git a/workflows/maxquant/mqpar_template_1.5.xml b/workflows/maxquant/mqpar_template_1.5.xml deleted file mode 100644 index 71e30cfd2..000000000 --- a/workflows/maxquant/mqpar_template_1.5.xml +++ /dev/null @@ -1,234 +0,0 @@ - - - Session1 - 1.5.6.8 - - 4 - false - - false - false - -1.7976931348623157E+308 - 1.7976931348623157E+308 - false - false - false - - PATH - - - FILE - - - 32767 - - - 0 - - - - 7 - 2 - false - false - true - 1 - NaN - NaN - MatchFromAndTo - 8 - true - 35 - true - 1.4 - 1.2 - false - 0 - 0 - 0 - - - - false - false - 3 - 6 - 100000 - 0 - 0 - false - false - true - false - 2 - true - 0 - 5 - 2 - 1 - - Trypsin/P - - - false - false - - Oxidation (M) - Acetyl (Protein N-term) - - false - - - - - false - - - true - 20 - 4.5 - true - 2 - true - 0.6 - 0.6 - true - false - 70 - false - - 0 - 0 - 0 - NaN - NaN - false - NaN - NaN - 0 - 0 - 0 - 0 - true - false - false - false - 0 - 0 - 0 - 0 - false - - PeptidesWithCleavedLinker - Standard - 0 - 0 - 0 - 0 - - - - Carbamidomethyl (C) - - - /home/projects/cpr_10006/people/henweb/fasta/UP000005640_9606.fasta - /home/projects/cpr_10006/people/henweb/fasta/UP000005640_9606_additional.fasta - - - - - 350000 - true - 0.005 - false - false - false - false - true - true - revert - all - true - 100 - 4600 - true - true - true - 0 - 6 - 0 - 40 - true - false - false - false - false - 0 - 0 - false - false - false - false - false - false - Species - false - 3 - false - true - false - true - false - 7 - 0.01 - 0.01 - 0.01 - 8 - 25 - true - 1 - 1 - 0 - false - true - false - - 2 - true - - Oxidation (M) - Acetyl (Protein N-term) - - 0 - 0 - 25 - 15 - - 200 - - - - 20 - 7 - 10 - - - 0.5 - 0.15 - 0.25 - - - 40 - 0.01 - 0.02 - - - 0.5 - 0.15 - 0.25 - - - 0 - 1 - none - diff --git a/workflows/maxquant/mqpar_template_1.6.xml b/workflows/maxquant/mqpar_template_1.6.xml deleted file mode 100644 index 930d718a9..000000000 --- a/workflows/maxquant/mqpar_template_1.6.xml +++ /dev/null @@ -1,473 +0,0 @@ - - - - - /home/projects/cpr_10006/people/henweb/fasta/UP000005640_9606.fasta - >.*\|(.*)\| - >.*\|(.*)\| - - - - 9606 - - - /home/projects/cpr_10006/people/henweb/fasta/UP000005640_9606_additional.fasta - >.*\|(.*)\| - >.*\|(.*)\| - - - - 9606 - - - - - - - - 350000 - True - 0.005 - False - False - True - True - revert - all - True - 4600 - True - True - True - 0 - 6 - 0 - 40 - True - False - False - False - False - 0 - 0 - False - False - False - False - 0 - False - False - False - False - False - False - Species - False - 3 - False - True - False - True - False - False - - - - 7 - 0.01 - 0.01 - 0.01 - 0.01 - 8 - 25 - True - 1 - 1 - 0 - False - True - False - - 2 - True - - Oxidation (M) - Acetyl (Protein N-term) - - 0 - 0 - 0 - 0 - 15 - 0 - 1 - - - 200 - False - True - True - True - True - True - True - False - False - False - True - False - 0 - 20 - - none - False - session1 - 1.6.12.0 - - - NUM_THREADS - 1 - - - - - -1.79589544172745E+308 - 1.79589544172745E+308 - False - False - False - False - False - False - False - - PATH - - - - - - 32767 - - - False - - - 0 - - - - - False - False - - - 0 - 7 - 2 - 1 - False - False - True - 1 - NaN - NaN - MatchFromAndTo - 0 - 8 - True - 35 - True - 1.4 - 1.2 - False - 0 - - - - Standard - False - 0 - 3 - 6 - 100000 - 0 - 0 - False - False - True - False - 2 - 0 - 5 - 2 - 1 - 0 - 0 - 0 - 0 - - Carbamidomethyl (C) - - - Trypsin/P - - - - 0 - False - False - - Oxidation (M) - Acetyl (Protein N-term) - - False - - - - - - - - - False - - - - - True - 20 - 4.5 - True - 2 - True - 0.6 - 0.6 - True - True - False - 70 - False - - 0 - 0 - 0 - NaN - NaN - False - NaN - NaN - 0 - 0 - 0 - 0 - True - False - True - False - - 0 - 6 - False - 0 - 0 - 0 - 0 - - - - - - - - - - False - True - 0.75 - 0 - - - - - - - - 20 - 20 - 0.85 - 2 - 2 - 7 - 1.99 - 0.4 - 0.65 - 0 - 6 - 1 - 3 - 0 - 0.8 - 0 - 1 - 0.5 - 0 - 3 - 25 - 260 - True - - - - - FTMS - 20 - True - 7 - True - 10 - True - True - 12 - 100 - True - True - True - True - False - - - ITMS - 0.5 - False - 0.15 - False - 0.25 - False - False - 8 - 100 - True - True - True - True - False - - - TOF - 40 - True - 0.01 - False - 0.02 - False - True - 10 - 100 - True - True - True - True - False - - - Unknown - 20 - True - 7 - True - 10 - True - True - 12 - 100 - True - True - True - True - False - - - - - CID - False - 1 - 1 - 1 - False - 1 - KRH - - - HCD - False - 1 - 1 - 1 - False - 1 - KRH - - - ETD - False - 1 - 1 - 1 - False - 1 - KRH - - - PQD - False - 1 - 1 - 1 - False - 1 - KRH - - - ETHCD - False - 1 - 1 - 1 - False - 1 - KRH - - - ETCID - False - 1 - 1 - 1 - False - 1 - KRH - - - UVPD - False - 1 - 1 - 1 - False - 1 - KRH - - - Unknown - False - 1 - 1 - 1 - False - 1 - KRH - - - diff --git a/workflows/maxquant/qsub-status.py b/workflows/maxquant/qsub-status.py deleted file mode 100644 index e6cdad7bb..000000000 --- a/workflows/maxquant/qsub-status.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python3 -# https://github.com/Snakemake-Profiles/pbs-torque/blob/master/%7B%7Bcookiecutter.profile_name%7D%7D/pbs-status.py -import sys -import subprocess -import xml.etree.cElementTree as ET - -jobid = sys.argv[1] - -try: - res = subprocess.run("qstat -f -x {}".format(jobid), check=True, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) - - xmldoc = ET.ElementTree(ET.fromstring(res.stdout.decode())).getroot() - job_state = xmldoc.findall('.//job_state')[0].text - - if job_state == "C": - exit_status = xmldoc.findall('.//exit_status')[0].text - if exit_status == '0': - print("success") - else: - print("failed") - else: - print("running") - -except (subprocess.CalledProcessError, IndexError, KeyboardInterrupt) as e: - print("failed") diff --git a/workflows/maxquant/run_sm_on_cluster.sh b/workflows/maxquant/run_sm_on_cluster.sh deleted file mode 100644 index acb0cada8..000000000 --- a/workflows/maxquant/run_sm_on_cluster.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -### Note: No commands may be executed until after the #PBS lines -### Account information -#PBS -W group_list=cpr_10006 -A cpr_10006 -### Job name (comment out the next line to get the name of the script used as the job name) -#PBS -N snakemake -### Output files (comment out the next 2 lines to get the job name used instead) -#PBS -e ${PBS_JOBNAME}.${PBS_JOBID}.e -#PBS -o ${PBS_JOBNAME}.${PBS_JOBID}.o -### Email notification: a=aborts, b=begins, e=ends, n=no notifications -#PBS -m ae -M henry.webel@cpr.ku.dk -### Number of nodes -#PBS -l nodes=1:ppn=4,mem=8gb -### Requesting timeformat is ::: -#PBS -l walltime=7:00:00:00 -### Forward all environment variables -### if authentification is done using pw in the environment -#PBS -V - - -# Go to the directory from where the job was submitted (initial directory is $HOME) -echo Working directory is $PBS_O_WORKDIR -cd $PBS_O_WORKDIR - - -snakemake --jobs 59 -k -p --latency-wait 60 --use-envmodules --rerun-incomplete \ ---cluster "qsub -l walltime={resources.walltime},nodes=1:ppn={threads},mem={resources.mem_mb}mb"\ -" -W group_list=cpr_10006 -A cpr_10006 -m f -V "\ -"-e {params.logdir} -o {params.logdir}" \ ---cluster-status "python qsub-status.py" && -echo "done" || -echo "failed" \ No newline at end of file diff --git a/workflows/maxquant/template_scripts/README.md b/workflows/maxquant/template_scripts/README.md deleted file mode 100644 index 904dc0637..000000000 --- a/workflows/maxquant/template_scripts/README.md +++ /dev/null @@ -1,12 +0,0 @@ -## Python Template -> Provided by Annelaura Bach - - -In the `template-scripts` folder is the `mq_job_template.sh` and -the `run_mq.py`: - -```bash -mq_job_template.sh # sumbitted to the queue -run_mq.py # script executing MaxQuant -``` - diff --git a/workflows/maxquant/template_scripts/mq_job_template.sh b/workflows/maxquant/template_scripts/mq_job_template.sh deleted file mode 100644 index 1b305c121..000000000 --- a/workflows/maxquant/template_scripts/mq_job_template.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh -### Note: No commands may be executed until after the #PBS lines -### Account information -#PBS -W group_list=cpr_10006 -A cpr_10006 -### Job name (comment out the next line to get the name of the script used as the job name) -#PBS -N -### Output files (comment out the next 2 lines to get the job name used instead) -#PBS -e ${PBS_JOBNAME}.e${PBS_JOBID} -#PBS -o ${PBS_JOBNAME}.o${PBS_JOBID} -### Email notification: a=aborts, b=begins, e=ends, n=no notifications -#PBS -m an -M henry.webel@cpr.ku.dk -### Number of nodes -#PBS -l nodes=1:ppn=20,mem=40gb -### Requesting timeformat is ::: -#PBS -l walltime=12:00:00 - -# Go to the directory from where the job was submitted (initial directory is $HOME) -module load tools -module load mono/6.8.0.105 -module load maxquant/1.6.7.0 - - -mono --version -#mono /home/projects/cpr_man/people/s155016/denoms/MaxQuant/bin/MaxQuantCmd.exe /home/projects/cpr_man/people/s155016/denoms/script/mqparfiles/mqpar_NAME.xml - -rm /home/projects/cpr_man/people/s155016/denoms/data/NAME/RAWFILE -echo "rawfile deleted" - -mv /home/projects/cpr_man/people/s155016/denoms/data/NAME/combined/txt/proteinGroups.txt /home/projects/cpr_man/people/s155016/denoms/result/proteinGroups/NAME_proteinGroups.txt -mv /home/projects/cpr_man/people/s155016/denoms/data/NAME/combined/txt/peptides.txt /home/projects/cpr_man/people/s155016/denoms/result/peptides/NAME_peptides.txt -echo "result files moved" - -echo "Done" diff --git a/workflows/maxquant/template_scripts/run_mq.py b/workflows/maxquant/template_scripts/run_mq.py deleted file mode 100644 index 246fa2e64..000000000 --- a/workflows/maxquant/template_scripts/run_mq.py +++ /dev/null @@ -1,55 +0,0 @@ -import pandas as pd -import os -from shutil import copyfile -from subprocess import call - -### prepare data frame with 3 columns: -# 'path' is the full path to the .raw file -# 'file' is the .raw file name e.g. 20191210_*.raw -# 'name' is the .raw file name without '.raw' e.g. 20191210_* - -# from os.listdir() - -DATADIR = '/home/projects/cpr_man/people/s155016/denoms/data/' -SCRIPTDIR = '/home/projects/cpr_man/people/s155016/denoms/script/' - -MQ_JOB_TEMPLATE = os.path.join(SCRIPTDIR, 'mq_job_template') - -MQ_PARAMETERS = 'mqpar_template.xml' -MQ_PARAMETERS = os.path.join(SCRIPTDIR, MQ_PARAMETERS) - -# df = pd.read_csv('my_df.tsv', sep ='\t', header = True) - -# loop over all runs -for i in range(df.shape[0]): - path, file, name = df.iloc[i] #replace by named parameters? - # create new directory - os.mkdir(DATADIR+name) - # copy file #ToDo: Why copy files? - copyfile(path, DATADIR + name + '/' + file) - print('rawfile copied') - # create mqpar with the correct path and experiment - mq_parameters_out_file = os.path.join(SCRIPTDIR, 'mqparfiles/mqpar_' + name + '.xml' ) - with open(MQ_PARAMETERS) as infile, open(mq_parameters_out_file, 'w') as outfile: - for line in infile: - line = line.replace('PATH', os.path.join(DATADIR, name, file)) - line = line.replace('FILE', file) - outfile.write(line) - outfile.close() - infile.close() - print('mqpar created') - # create mq_job file with the correct paths etc. - mq_job_file = os.path.join(SCRIPTDIR, 'mqjobs/mq_job_' + name) - with open(MQ_JOB_TEMPLATE) as infile, open(mq_job_file, 'w') as outfile: - for line in infile: - line = line.replace('NAME', name) - line = line.replace('RAWFILE', file) - outfile.write(line) - outfile.close() - infile.close() - print('mqjob created') - # run mqjob - os.chdir(os.path.join(DATADIR, name)) - queue_command = 'qsub '+ mq_job_file - return_code = call(queue_command, shell=True) - print('job {} queued out of 528'.format(i+1)) diff --git a/workflows/metadata/.gitignore b/workflows/metadata/.gitignore deleted file mode 100644 index dfb926ad7..000000000 --- a/workflows/metadata/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -tmp -jsons -txts -metadata -config -!config/ald_study -rawfile_metadata*.json \ No newline at end of file diff --git a/workflows/metadata/README.md b/workflows/metadata/README.md deleted file mode 100644 index 7f12790de..000000000 --- a/workflows/metadata/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# Metadata workflow - -Get metadata from ThermoFischer proteomics raw files using -[`ThermoRawFileParser`](https://github.com/compomics/ThermoRawFileParser) - -## Output - -- both json and txt data format into `jsons` and `txts` folder -- create combined `rawfile_metadata.json` (needs to be deleted if files are added) - -## Configfile - -add a `config/files.yaml` in [config](config): - -```yaml -remote_in: erda:folder/path -out_folder: metadata -thermo_raw_file_parser_exe: mono path/to/ThermoRawFileParser/ThermoRawFileParser.exe -files: -- remote/path/file1.raw -- remote/path/file2.raw -``` - -The list of files is fetched from [`project/00_2_hela_all_raw_files.ipynb`](../../project/00_2_hela_all_raw_files.ipynb) notebook. - - -Then invoke the workflow with the list of config files - -```bash -# dry-run -snakemake --configfiles config/ald_study/config.yaml config/ald_study/excluded.yaml -p -n -``` - - -### Excluded files - -Some files might be corrupted and not be processed by `ThermoRawFileParser`. These can be -excluded based on the `tmp` folder - -```bash -# check files -echo 'excluded:' > config/excluded_$(date +"%Y%m%d").yaml -find tmp -name '*.raw*' | awk 'sub(/^.{4}/," ? ")' >> config/excluded_$(date +"%Y%m%d").yaml - -# potentially add these to the workflow exclusion files: -find tmp -name '*.raw*' | awk 'sub(/^.{4}/," ? ")' >> config/excluded.yaml -# rm -r tmp/* # remove excluded files -``` - -these files are ignored in the workflow (configured as a python set). - -## Setup - -- download and unzip [`ThermoRawFileParser`](https://github.com/compomics/ThermoRawFileParser) -- add path to `exe` to config - -```bash -# sudo apt-get update -sudo apt install mono-complete -conda activate vaep # actually only snakemake needed -snakemake -n # see job listing -``` - -## zip outputs - - -```bash -# could be part of snakemake process -zip -r metadata.zip txt jsons -``` \ No newline at end of file diff --git a/workflows/metadata/Snakefile b/workflows/metadata/Snakefile deleted file mode 100644 index 45a7bcda3..000000000 --- a/workflows/metadata/Snakefile +++ /dev/null @@ -1,85 +0,0 @@ -from pathlib import Path, PurePosixPath -configfile: "config/other.yaml" -configfile: "config/excluded.yaml" - -files = [PurePosixPath(p) for p in config['files'] if p not in config['excluded']] -files = [p.parent/ p.stem for p in files] - -CSV_OUT = config['out_csv'] - -rule all: - input: - # config['out_folder'] + "/rawfile_metadata.json" - CSV_OUT - -rule build_csv: - input: - data = config['out_folder'] + "/rawfile_metadata.json", - nb = 'read_metadata.ipynb' - output: - csv = CSV_OUT, - nb = config['out_folder'] + '/read_metadata_executed.ipynb' - shell: - "papermill {input.nb} {output.nb}" - " -p rawfile_metadata_in {input.data}" - " -p rawfile_metadata_out {output.csv}" - - -rule combine_json: - input: - expand( - config['out_folder'] + "/jsons/{file}-metadata.json", - file=files - ) - output: - out = config['out_folder'] + "/rawfile_metadata.json" - threads: - 1 - resources: - load=1 # multiplexing - run: - import json - import yaml - from pathlib import Path - metadata = {} - for fname in input: - key = Path(fname).name.split('-metadata.json')[0] - with open(fname) as f: - metadata[key] = json.load(f) - # metadata[key] = yaml.safe_load(f) # yaml can also read json (but add. dependency) - with open(output.out, 'w') as f: - json.dump(metadata, f) - - -rule parse_rawfile_metadata: - input: - raw = config['folder_raw'] + '{file}.raw' - output: - json = config['out_folder'] + "/jsons/{file}-metadata.json", - txt = config['out_folder'] + "/txts/{file}-metadata.txt" - params: - thermo_exe = config['thermo_raw_file_parser_exe'] - threads: - 1 - resources: - load=1 - shell: - # multiline does not work on windows workstation. ("""....""") - "{params.thermo_exe} -i {input.raw:q} -m 0 -b {output.json:q}" - " & {params.thermo_exe} -i {input.raw:q} -m 1 -b {output.txt:q}" - - -rule download: - output: - raw_local = temp(config['folder_raw'] + '/{file}.raw') - params: - remote = config['remote_in'], - raw_remote = '{file}.raw' - threads: - 1 - resources: - load=10 # erda: multiplexing allows 10 max concurrent sessions - shell: - """ - sftp -B 258048 {params.remote} <<< 'get "{params.raw_remote}" "{output.raw_local}"' - """ \ No newline at end of file diff --git a/workflows/metadata/config/README.md b/workflows/metadata/config/README.md deleted file mode 100644 index 6827dccd0..000000000 --- a/workflows/metadata/config/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Configfiles - -add a `config/example.yaml` - -```yaml -remote_in: erda:folder/path -out_folder: metadata -thermo_raw_file_parser_exe: mono path/to/ThermoRawFileParser/ThermoRawFileParser.exe -files: -- remote/path/file1.raw -- remote/path/file2.raw -``` \ No newline at end of file diff --git a/workflows/metadata/config/ald_study/config.yaml b/workflows/metadata/config/ald_study/config.yaml deleted file mode 100644 index 24a0bfe18..000000000 --- a/workflows/metadata/config/ald_study/config.yaml +++ /dev/null @@ -1,676 +0,0 @@ -remote_in: . -folder_raw: "E:\\data\\Lili\\ALD upgrade\\" -out_folder: metadata/ald -out_csv: ../../project/data/single_datasets/ald_metadata_rawfiles.csv -thermo_raw_file_parser_exe: D:\Users\clilniu\Documents\secure_cloud_tools\ThermoRawFileParser\ThermoRawFileParser.exe -files: - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A1_20210920175431.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A2.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A3.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A4.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A5.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A6.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A7.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A8.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A9.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A10.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A11.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_A12.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B1.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B2.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B3.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B4.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B5.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B6.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B7.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B8.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B9.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B10.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B11.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_B12.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C1.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C2.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C3.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C4.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C5.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C6.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C7.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C8.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C9.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C10.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C11.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_C12.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_D2.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_D4.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_D5.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_D6.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_D7.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_D8.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_D1.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_D9.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_D10.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_D11.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_D12.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_E3.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_E4.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_E5.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_E6.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_E7.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_E2.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_E8.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_E9.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_E10.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_E11.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_E12.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F1.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F2.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F3.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F4.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F5.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F6.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F7.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F8.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F9.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F10.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F11.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_F12.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G1.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G2.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G3.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G4.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G5.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G6.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G7.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G8.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G9.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G10.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G11.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_G12.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H1.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H2.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H3.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H4.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H5.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H6.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H7.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H8.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H9.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H10.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H11.raw - - 20210919_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate1_H12.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A1.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A2.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A3.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A4.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A5.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A6.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A7.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A8.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A9.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A10.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A11.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_A12.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B1.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B2.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B3.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B4.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B5.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B6.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B7.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B8.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B9.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B10.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B11.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_B12.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C2.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C3.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C4.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C5.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C6.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C7.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C8.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C9.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C10.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C11.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C12.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D1.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D2.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D3.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D4.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D5.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D6.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D7.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D8.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D9.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D10.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D11.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_D12.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E1.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E2.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E3.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E4.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E5.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E6.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E7.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E8.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E9.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E10.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E11.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_E12.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F1.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F2.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F3.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F4.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F5.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F6.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F7.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F8.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F9.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F10.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F11.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_F12.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G1.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G2.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G3.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G4.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G5.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G6.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G7.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G8.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G9.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G10.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G11.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_G12.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H1.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H2.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H3.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H4.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H5.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H6.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H7.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H8.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H9.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H10.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H11.raw - - 20210921_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_H12.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A1.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A2.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A3.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A4.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A5.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A6.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A7.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A8.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A9.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A10.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A11.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_A12.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B1.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B2.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B3.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B4.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B5.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B6.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B7.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B8.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B9.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B10.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B11.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_B12.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C1.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C2.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C3.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C4.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C5.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C6.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C7.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C8.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C9.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C10.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C11.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_C12.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D1.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D2.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D3.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D4.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D5.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D6.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D7.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D8.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D9.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D10.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D11.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_D12.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E1.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E2.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E3.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E4.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E5.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E6.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E7.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E8.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E9.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E10.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E11.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_E12.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F1.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F2.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F3.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F4.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F5.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F6.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F7.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F8.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F9.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F10.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F11.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_F12.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G1.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G2.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G3.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G4.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G5.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G6.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G7.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G8.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G9.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G10.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G11.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_G12.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_H1.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_H3.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_H4.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_H5.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_H6.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_H7.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_H8.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_H9.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_H10.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_H11.raw - - 20210923_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate3_H12.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A1.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A2.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A3.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A4.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A5.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A6.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A7.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A8.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A9.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A10.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A11.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_A12.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B1.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B2.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B3.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B4.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B5.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B6.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B7.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B8.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B9.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B10.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B11.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_B12.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C1.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C2.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C3.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C4.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C5.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C6.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C7.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C8.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C9.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C10.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C11.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_C12.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D1.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D2.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D3.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D4.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D5.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D6.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D7.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D8.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D9.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D10.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D11.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_D12.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_E1.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_E2.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_E4.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_E5.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_E6.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_E7.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_E8.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_E9.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_E10.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_E11.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_E12.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F1.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F2.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F3.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F4.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F5.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F6.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F7.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F8.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F9.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F10.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F11.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_F12.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G1.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G2.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G3.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G4.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G5.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G6.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G7.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G9.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G10.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G11.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G12.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H1.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H2.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H3.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H4.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H5.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H6.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H7.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H8.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H9.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H10.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H11.raw - - 20210925_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_H12.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A1.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A2.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A3.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A4.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A5.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A6.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A7.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A8.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A9.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A10.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A11.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_A12.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_B1.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_B2.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_B3.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_B4.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_B5.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_B6.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_B8.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_B9.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_B10.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_B11.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_B12.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_C2.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_C3.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_C4.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_C5.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_C6.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_C7.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_C8.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_C9.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_C10.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_C11.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_C12.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D1.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D2.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D3.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D4.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D7.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D8.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D9.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D10.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D11.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D12.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E1.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E2.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E3.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E4.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E5.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E6.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E7.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E8.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E9.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E10.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E11.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_E12.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_F1.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_F2.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_F3.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_F5.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_F6.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_F7.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_F8.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_F9.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_F10.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_F11.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_F12.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G2.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G3.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G4.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G5.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G6.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G7.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G8.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G9.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G10.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G11.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G12.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H1.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H2.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H3.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H4.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H5.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H6.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H7.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H8.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H9.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H10.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H11.raw - - 20210927_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_H12.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A1.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A2.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A3.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A4.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A5.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A6.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A7.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A8.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A9.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A10.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A11.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_A12.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B1.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B2.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B3.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B4.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B5.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B6.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B7.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B8.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B9.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B10.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B11.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_B12.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C1.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C2.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C3.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C4.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C5.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C6.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C7.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C8.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C9.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C10.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C11.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_C12.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D1.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D2.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D3.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D4.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D5.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D6.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D7.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D8.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D9.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D10.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D11.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_D12.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E1.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E2.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E3.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E4.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E5.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E6.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E7.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E8.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E9.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E10.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E11.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_E12.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F1.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F2.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F3.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F4.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F5.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F6.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F7.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F8.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F9.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F10.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F11.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_F12.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G1.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G2.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G3.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G4.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G5.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G6.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G7.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G8.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G9.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G10.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G11.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_G12.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H1.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H2.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H3.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H4.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H5.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H6.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H7.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H8.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H9.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H10.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H11.raw - - 20210929_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate6_H12.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A1.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A2.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A3.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A4.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A5.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A6.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A7.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A8.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A9.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A10.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A11.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_A12.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_B1.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_B2.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_B3.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_B4.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_B5.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_B7.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_B8.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_B9.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_B10.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_B11.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_B12.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C1.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C2.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C3.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C4.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C5.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C6.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C7.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C8.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C9.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C10.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C11.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_C12.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_D1.raw - - 20211001_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate7_D2.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A1.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A2.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A3.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A4.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A5.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A6.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A7.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A8.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A9.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A10.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A11.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_A12.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B1.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B2.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B3.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B4.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B5.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B6.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B7.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B8.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B9.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B10.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B11.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_B12.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C1.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C2.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C3.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C4.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C5.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C6.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C7.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C8.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C9.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C10.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C11.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_C12.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D1.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D2.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D3.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D4.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D5.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D6.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D7.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D8.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D9.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D10.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D11.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_D12.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E1.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E2.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E3.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E4.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E5.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E7.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E8.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E9.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E10.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E11.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E12.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_F1.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_F2.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_F3.raw - - 20211003_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_H12.raw - - 20211014_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C1.raw - - 20211014_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate4_G8.raw - - 20211014_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D5.raw - - 20211014_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_D6.raw - - 20211014_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate5_G1.raw - - 20211014_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate8_E6.raw diff --git a/workflows/metadata/config/ald_study/excluded.yaml b/workflows/metadata/config/ald_study/excluded.yaml deleted file mode 100644 index ed7b46aa9..000000000 --- a/workflows/metadata/config/ald_study/excluded.yaml +++ /dev/null @@ -1,3 +0,0 @@ -excluded: -# ERROR Unable to access the RAW file using the native Thermo library. - ? 20211014_EXPL3_PRIEvosep2_LiNi_SA_Plasma_ALD_Plate2_C1.raw \ No newline at end of file diff --git a/workflows/metadata/config/example.yaml b/workflows/metadata/config/example.yaml deleted file mode 100644 index 0bb9713d3..000000000 --- a/workflows/metadata/config/example.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# example for all config entires -# can be separated into several configfiles for snakemake -remote_in: erda:folder/path -out_folder: metadata -thermo_raw_file_parser_exe: mono path/to/ThermoRawFileParser/ThermoRawFileParser.exe -files: -- remote/path/file1.raw -- remote/path/file2.raw \ No newline at end of file diff --git a/workflows/metadata/config/excluded.yaml b/workflows/metadata/config/excluded.yaml deleted file mode 100644 index 43cf24f5d..000000000 --- a/workflows/metadata/config/excluded.yaml +++ /dev/null @@ -1,2 +0,0 @@ -excluded: - ? \ No newline at end of file diff --git a/workflows/metadata/read_metadata.ipynb b/workflows/metadata/read_metadata.ipynb deleted file mode 100644 index 1021c3fa4..000000000 --- a/workflows/metadata/read_metadata.ipynb +++ /dev/null @@ -1,314 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Machine metadata in pandas DataFrame" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "import pathlib\n", - "import pprint\n", - "\n", - "import pandas as pd\n", - "pd.options.display.max_columns = 32\n", - "\n", - "import vaep.utils\n", - "import vaep.pandas" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "configs:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "parameters" - ] - }, - "outputs": [], - "source": [ - "DATA_PROJECT = pathlib.Path('../../project/data')\n", - "\n", - "rawfile_metadata_in = 'rawfile_metadata.json'\n", - "rawfile_metadata_out = DATA_PROJECT / 'rawfile_metadata.csv'\n", - "rawfile_metadata_in" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "read raw file created by snakemake workflow" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "with open(rawfile_metadata_in) as f:\n", - " data = json.load(f)\n", - "\n", - "key_sampled = vaep.utils.sample_iterable(data, 1)[0]\n", - "sample = data[key_sampled]\n", - "pprint.pprint(sample)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sample.keys()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "- essentially the all data is a dictionary with for keys: `['accession', 'cvLabel', 'name', 'value']`\n", - "- pick for each type of entry in `['FileProperties', 'InstrumentProperties', 'MsData', 'ScanSettings', 'SampleData']` \n", - " - the `name` and `value` for a single in a list of entries" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "parsed = {}\n", - "for sample_id, meta_json in data.items():\n", - " selected = {}\n", - " for k, entries in meta_json.items():\n", - " for entry in entries:\n", - " selected[k, entry['name']] = entry['value']\n", - " parsed[sample_id] = selected\n", - "pprint.pprint(parsed[sample_id])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# simple strings (not as shown by pprint)\n", - "(parsed[sample_id][('InstrumentProperties', 'instrument serial number')],\n", - " parsed[sample_id][('InstrumentProperties', 'Thermo Scientific instrument model')])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Explicitly specifying the default dtypese here once. These are set when the data is read from the json file created in this script `rawfile_metadata_out`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# # df.dtypes.to_dict() needed parsing\n", - "# from numpy import dtype\n", - "# types = {\n", - "# ('FileProperties', 'Pathname'): dtype('O'),\n", - "# ('FileProperties', 'Version'): dtype('int64'),\n", - "# ('FileProperties', 'Content Creation Date'): dtype('O'),\n", - "# ('InstrumentProperties', 'Thermo Scientific instrument model'): dtype('O'),\n", - "# ('InstrumentProperties', 'instrument attribute'): dtype('O'),\n", - "# ('InstrumentProperties', 'instrument serial number'): dtype('O'),\n", - "# ('InstrumentProperties', 'Software Version'): dtype('O'),\n", - "# ('InstrumentProperties', 'firmware version'): dtype('O'),\n", - "# ('MsData', 'Number of MS1 spectra'): dtype('int64'),\n", - "# ('MsData', 'Number of MS2 spectra'): dtype('float64'),\n", - "# ('MsData', 'MS min charge'): dtype('int64'),\n", - "# ('MsData', 'MS max charge'): dtype('int64'),\n", - "# ('MsData', 'MS min RT'): dtype('float64'),\n", - "# ('MsData', 'MS max RT'): dtype('float64'),\n", - "# ('MsData', 'MS min MZ'): dtype('float64'),\n", - "# ('MsData', 'MS max MZ'): dtype('float64'),\n", - "# ('ScanSettings', 'scan start time'): dtype('float64'),\n", - "# ('ScanSettings', 'mass resolution'): dtype('float64'),\n", - "# ('ScanSettings', 'mass unit'): dtype('O'),\n", - "# ('ScanSettings', 'Number of scans'): dtype('int64'),\n", - "# ('ScanSettings', 'MS scan range'): dtype('O'),\n", - "# ('ScanSettings', 'Retention time range'): dtype('O'),\n", - "# ('ScanSettings', 'Mz range'): dtype('O'),\n", - "# ('ScanSettings', 'beam-type collision-induced dissociation'): dtype('O'),\n", - "# ('SampleData', 'sample number'): dtype('O'),\n", - "# ('SampleData', 'Type'): dtype('O'),\n", - "# ('SampleData', 'Vial'): dtype('O'),\n", - "# ('SampleData', 'injection volume setting'): dtype('float64'),\n", - "# ('SampleData', 'Row'): dtype('float64'),\n", - "# ('SampleData', 'dilution factor'): dtype('int64'), # fails with NA\n", - "# ('SampleData', 'sample name'): dtype('O'),\n", - "# ('SampleData', 'Comment'): dtype('O'),\n", - "# }" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = pd.DataFrame.from_dict(parsed, orient='index')\n", - "df.columns.names = ['category', 'item']\n", - "df.index.name = 'Sample ID'\n", - "\n", - "# df = df.astype(types)\n", - "\n", - "# write and read to check that this works and convert dtypes directly\n", - "# jso n format cannot preserve multiindex columns\n", - "df.to_csv(rawfile_metadata_out)\n", - "df = pd.read_csv(rawfile_metadata_out, header=[0,1], index_col=0) # read data elsewhere, set dtypes automatically, multiindex headers\n", - "df.describe(include='all')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df.dtypes" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "columns_selected = [\n", - " # ('FileProperties', 'Pathname'),\n", - " # ('FileProperties', 'Version'),\n", - " # ('FileProperties', 'Content Creation Date'),\n", - " ('InstrumentProperties', 'Thermo Scientific instrument model'),\n", - " ('InstrumentProperties', 'instrument attribute'),\n", - " ('InstrumentProperties', 'instrument serial number'),\n", - " # ('InstrumentProperties', 'Software Version'),\n", - " # ('InstrumentProperties', 'firmware version'),\n", - " # ('MsData', 'Number of MS1 spectra'),\n", - " # ('MsData', 'Number of MS2 spectra')\n", - " ('MsData', 'MS min charge'),\n", - " ('MsData', 'MS max charge'),\n", - " ('MsData', 'MS min RT'),\n", - " ('MsData', 'MS max RT'),\n", - " ('MsData', 'MS min MZ'),\n", - " ('MsData', 'MS max MZ'),\n", - " # ('ScanSettings', 'scan start time'),\n", - " ('ScanSettings', 'mass resolution'),\n", - " # ('ScanSettings', 'mass unit'),\n", - " # ('ScanSettings', 'Number of scans'),\n", - " # ('ScanSettings', 'MS scan range'),\n", - " ('ScanSettings', 'Retention time range'),\n", - " ('ScanSettings', 'Mz range'),\n", - " ('ScanSettings', 'beam-type collision-induced dissociation'),\n", - " # ('SampleData', 'sample number'),\n", - " # ('SampleData', 'Type'),\n", - " ('SampleData', 'Vial'),\n", - " # ('SampleData', 'injection volume setting'),\n", - " # ('SampleData', 'Row'),\n", - " ('SampleData', 'dilution factor'),\n", - " # ('SampleData', 'sample name'),\n", - " # ('SampleData', 'Comment')\n", - "]\n", - "\n", - "df[columns_selected]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df[columns_selected].describe(include='all')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Test that dtypes of reloaded data are the same. Documents how to load metadata" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# import numpy.testing as npt\n", - "\n", - "# desired = df.dtypes.to_dict()\n", - "# # read data elsewhere, set dtypes automatically\n", - "# df_new = pd.read_csv(rawfile_metadata_out, header=[0, 1], index_col=0)\n", - "# actual = df_new.dtypes.to_dict()\n", - "# npt.assert_equal(actual, desired)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.8.13 ('vaep')", - "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.8.13" - }, - "vscode": { - "interpreter": { - "hash": "cf83e9cb890c7f96eb0ae04f39a82254555f56a1a0ed2f03b23a8b40fe6cd31c" - } - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} From 02b2d9fac521553c3e134dcdd7bffb2de1e196e8 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 16 Oct 2023 15:15:39 +0200 Subject: [PATCH 27/70] :construction: update Snakefile v2 - cluster execution and renamed files - format --- .../knn_comparison/ald_pgs_all/config.yaml | 30 +++--- project/workflow/Snakefile_v2 | 97 ++++++++++++++----- 2 files changed, 86 insertions(+), 41 deletions(-) diff --git a/project/config/knn_comparison/ald_pgs_all/config.yaml b/project/config/knn_comparison/ald_pgs_all/config.yaml index d7b966561..9d371c2bb 100644 --- a/project/config/knn_comparison/ald_pgs_all/config.yaml +++ b/project/config/knn_comparison/ald_pgs_all/config.yaml @@ -5,19 +5,19 @@ fn_rawfile_metadata: data/ALD_study/processed/raw_meta.csv file_format: pkl cuda: False models: - - Median: - model: Median - - 3NN: - neighbors: 3 - model: KNN - - 5NN: - neighbors: 5 - model: KNN - - 10NN: - neighbors: 10 - model: KNN - - 15NN: - neighbors: 15 - model: KNN + - Median: + model: Median + - 3NN: + neighbors: 3 + model: KNN + - 5NN: + neighbors: 5 + model: KNN + - 10NN: + neighbors: 10 + model: KNN + - 15NN: + neighbors: 15 + model: KNN NAGuideR_methods: - - KNN_IMPUTE + - KNN_IMPUTE diff --git a/project/workflow/Snakefile_v2 b/project/workflow/Snakefile_v2 index b69d783fc..47f3ca513 100644 --- a/project/workflow/Snakefile_v2 +++ b/project/workflow/Snakefile_v2 @@ -3,16 +3,31 @@ Document how all the notebooks for a single experiment are connected. """ from snakemake.logging import logger + configfile: "config/single_dev_dataset/proteinGroups_N50/config.yaml" + +MAX_WALLTIME = "24:00:00" +# Thinnode resources sharing: 40 cores and 196 GB RAM (minus 2GB for snakemake) +# JOB_RAM_MB = int(204_800 / 40 * config['THREATS_MQ']) +JOB_RAM_MB = "4gb" folder_experiment = config["folder_experiment"] logger.info(f"{folder_experiment = }") +# local rules are excuted in the process (job) running snakemake +localrules: + all, + comparison, + transform_NAGuideR_predictions, + transform_data_to_wide_format, + create_splits, + + rule all: input: - f"{folder_experiment}/figures/errors_binned_by_int_test.pdf", - f"{folder_experiment}/01_2_performance_summary.xlsx" + f"{folder_experiment}/figures/2_1_test_errors_binned_by_int.pdf", + f"{folder_experiment}/01_2_performance_summary.xlsx", nb = "01_2_performance_plots.ipynb" @@ -33,28 +48,26 @@ else: if config["NAGuideR_methods"]: MODELS += config["NAGuideR_methods"] -print(model_configs) +nb_stem = "01_2_performance_summary" -print(MODELS) - -# import pdb; pdb.set_trace() - rule comparison: input: nb=nb, runs=expand( "{folder_experiment}/preds/pred_test_{model}.csv", - folder_experiment=folder_experiment, + folder_experiment=config["folder_experiment"], model=MODELS, ), output: - xlsx="{folder_experiment}/01_2_performance_summary.xlsx", - pdf="{folder_experiment}/figures/errors_binned_by_int_test.pdf", + xlsx=f"{{folder_experiment}}/{nb_stem}.xlsx", + pdf="{folder_experiment}/figures/2_1_test_errors_binned_by_int.pdf", nb="{folder_experiment}" f"/{nb}", params: meta_data=config["fn_rawfile_metadata"], models=",".join(MODELS), + err=f"{{folder_experiment}}/{nb_stem}.e", + out=f"{{folder_experiment}}/{nb_stem}.o", shell: "papermill {input.nb} {output.nb}" " -r fn_rawfile_metadata {params.meta_data:q}" @@ -62,48 +75,63 @@ rule comparison: " -r models {params.models:q}" " && jupyter nbconvert --to html {output.nb}" + ########################################################################################## # train NaGuideR methods nb_stem = "01_1_transfer_NAGuideR_pred" + + rule transform_NAGuideR_predictions: - input: + input: dumps=expand( "{{folder_experiment}}/preds/pred_all_{method}.csv", method=config["NAGuideR_methods"], ), nb=f"{nb_stem}.ipynb", output: - # "{{folder_experiment}}/preds/pred_real_na_{method}.csv"), - expand( ( - "{{folder_experiment}}/preds/pred_val_{method}.csv", - "{{folder_experiment}}/preds/pred_test_{method}.csv"), + # "{{folder_experiment}}/preds/pred_real_na_{method}.csv"), + expand( + ( + "{{folder_experiment}}/preds/pred_val_{method}.csv", + "{{folder_experiment}}/preds/pred_test_{method}.csv", + ), method=config["NAGuideR_methods"], ), nb="{folder_experiment}/01_1_transfer_NAGuideR_pred.ipynb", benchmark: - "{folder_experiment}/"f"{nb_stem}.tsv", + "{folder_experiment}/" f"{nb_stem}.tsv" params: + err=f"{{folder_experiment}}/{nb_stem}.e", + out=f"{{folder_experiment}}/{nb_stem}.o", folder_experiment="{folder_experiment}", # https://snakemake.readthedocs.io/en/stable/snakefiles/rules.html#non-file-parameters-for-rules - dumps_as_str=lambda wildcards, input: ','.join(input.dumps) + dumps_as_str=lambda wildcards, input: ",".join(input.dumps), shell: "papermill {input.nb} {output.nb}" " -r folder_experiment {params.folder_experiment}" " -p dumps {params.dumps_as_str}" " && jupyter nbconvert --to html {output.nb}" + rule train_NAGuideR_model: input: nb="01_1_train_NAGuideR_methods.ipynb", train_split="{folder_experiment}/data/data_wide_sample_cols.csv", output: nb="{folder_experiment}/01_1_train_NAGuideR_{method}.ipynb", - dump=temp("{folder_experiment}/preds/pred_all_{method}.csv") + dump="{folder_experiment}/preds/pred_all_{method}.csv", + resources: + mem_mb=JOB_RAM_MB, + walltime=MAX_WALLTIME, + threads: 1 # R is single threaded benchmark: "{folder_experiment}/01_1_train_NAGuideR_{method}.tsv" params: + err="{folder_experiment}/01_1_train_NAGuideR_{method}.e", + out="{folder_experiment}/01_1_train_NAGuideR_{method}.o", folder_experiment="{folder_experiment}", method="{method}", + name="{method}", shell: "papermill {input.nb} {output.nb}" " -r train_split {input.train_split}" @@ -111,20 +139,27 @@ rule train_NAGuideR_model: " -r folder_experiment {params.folder_experiment}" " && jupyter nbconvert --to html {output.nb}" + +nb_stem = "01_0_transform_data_to_wide_format" + + rule transform_data_to_wide_format: input: - nb="01_0_transform_data_to_wide_format.ipynb", + nb=f"{nb_stem}.ipynb", train_split="{folder_experiment}/data/train_X.csv", output: nb="{folder_experiment}/01_0_transform_data_to_wide_format.ipynb", - train_split=temp("{folder_experiment}/data/data_wide_sample_cols.csv"), + train_split="{folder_experiment}/data/data_wide_sample_cols.csv", params: folder_experiment="{folder_experiment}", + err=f"{{folder_experiment}}/{nb_stem}.e", + out=f"{{folder_experiment}}/{nb_stem}.o", shell: "papermill {input.nb} {output.nb}" " -r folder_experiment {params.folder_experiment}" " && jupyter nbconvert --to html {output.nb}" + ########################################################################################## # train models in python rule train_models: @@ -134,12 +169,15 @@ rule train_models: configfile=config["config_train"], output: nb="{folder_experiment}/01_1_train_{model}.ipynb", - pred="{folder_experiment}/preds/pred_test_{model}.csv" + pred="{folder_experiment}/preds/pred_test_{model}.csv", benchmark: "{folder_experiment}/01_1_train_{model}.tsv" params: folder_experiment="{folder_experiment}", meta_data=config["fn_rawfile_metadata"], + err="{folder_experiment}/01_1_train_{model}.e", + out="{folder_experiment}/01_1_train_{model}.o", + name="{model}", shell: "papermill {input.nb} {output.nb}" " -f {input.configfile}" @@ -148,32 +186,39 @@ rule train_models: " -r model_key {wildcards.model}" " && jupyter nbconvert --to html {output.nb}" + ########################################################################################## # create config file dumps for each model + rule dump_train_config: output: - configfile=config["config_train"] + configfile=config["config_train"], run: import yaml + with open(output.configfile, "w") as f: yaml.dump(model_configs[wildcards.model], f) + ########################################################################################## # Create Data splits # separate workflow by level -> provide custom configs -nb = "01_0_split_data.ipynb" +nb_stem = "01_0_split_data" + rule create_splits: input: - nb=nb, - configfile=config["config_split"], + nb=f"{nb_stem}.ipynb", + configfile=f"{folder_experiment}/{nb_stem}.yaml", output: train_split="{folder_experiment}/data/train_X.csv", - nb="{folder_experiment}" f"/{nb}", + nb="{folder_experiment}" f"/{nb_stem}.ipynb", params: folder_experiment="{folder_experiment}", meta_data=config["fn_rawfile_metadata"], + err=f"{{folder_experiment}}/{nb_stem}.e", + out=f"{{folder_experiment}}/{nb_stem}.o", shell: "papermill {input.nb} {output.nb}" " -f {input.configfile}" From 288d78e8db76bcd8436e2f0f6c3eb3f0459cd1b4 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 16 Oct 2023 15:35:40 +0200 Subject: [PATCH 28/70] :sparkles: Integrate data splitting config into main config - allow to set frac_mnar from commandline using: --config frac_mnar=.5 - dump created data config using separate rule (into experiment folder) --- .../knn_comparison/ald_pgs_all/config.yaml | 8 ++++++- .../knn_comparison/ald_pgs_all/split.yaml | 6 ----- project/workflow/Snakefile_v2 | 24 ++++++++++++++++--- 3 files changed, 28 insertions(+), 10 deletions(-) delete mode 100644 project/config/knn_comparison/ald_pgs_all/split.yaml diff --git a/project/config/knn_comparison/ald_pgs_all/config.yaml b/project/config/knn_comparison/ald_pgs_all/config.yaml index 9d371c2bb..149413972 100644 --- a/project/config/knn_comparison/ald_pgs_all/config.yaml +++ b/project/config/knn_comparison/ald_pgs_all/config.yaml @@ -1,9 +1,15 @@ -config_split: config/knn_comparison/ald_pgs_all/split.yaml config_train: runs/knn_comparison/ald_pgs_all/configs_train/train_{model}.yaml folder_experiment: runs/knn_comparison/ald_pgs_all fn_rawfile_metadata: data/ALD_study/processed/raw_meta.csv file_format: pkl cuda: False +split_data: + FN_INTENSITIES: data/ALD_study/processed/ald_plasma_proteinGroups.pkl + sample_completeness: 0.5 + min_RT_time: 20 + column_names: + - PG.ProteinAccessions +# frac_mnar: 0.0 models: - Median: model: Median diff --git a/project/config/knn_comparison/ald_pgs_all/split.yaml b/project/config/knn_comparison/ald_pgs_all/split.yaml deleted file mode 100644 index d2c0b6793..000000000 --- a/project/config/knn_comparison/ald_pgs_all/split.yaml +++ /dev/null @@ -1,6 +0,0 @@ -FN_INTENSITIES: data/ALD_study/processed/ald_plasma_proteinGroups.pkl -# fn_rawfile_metadata: data/ALD_study/processed/raw_meta.csv -sample_completeness: 0.5 -min_RT_time: 20 -column_names: - - PG.ProteinAccessions \ No newline at end of file diff --git a/project/workflow/Snakefile_v2 b/project/workflow/Snakefile_v2 index 47f3ca513..6dfb4e28a 100644 --- a/project/workflow/Snakefile_v2 +++ b/project/workflow/Snakefile_v2 @@ -32,8 +32,10 @@ rule all: nb = "01_2_performance_plots.ipynb" -print(config["models"]) +if "frac_mnar" in config: + config["split_data"]["frac_mnar"] = config["frac_mnar"] +# print(config['split_data']) # MODELS = config["models"].copy() MODELS = list() @@ -164,7 +166,9 @@ rule transform_data_to_wide_format: # train models in python rule train_models: input: - nb=lambda wildcards: "01_1_train_{}.ipynb".format(model_configs[wildcards.model]["model"]), + nb=lambda wildcards: "01_1_train_{}.ipynb".format( + model_configs[wildcards.model]["model"] + ), train_split="{folder_experiment}/data/train_X.csv", configfile=config["config_train"], output: @@ -224,4 +228,18 @@ rule create_splits: " -f {input.configfile}" " -r folder_experiment {params.folder_experiment}" " -p fn_rawfile_metadata {params.meta_data}" - " && jupyter nbconvert --to html {output.nb}" \ No newline at end of file + " && jupyter nbconvert --to html {output.nb}" + + +########################################################################################## +# create config file dumps for each model + + +rule dump_split_config: + output: + configfile=f"{folder_experiment}/{nb_stem}.yaml", + run: + import yaml + + with open(output.configfile, "w") as f: + yaml.dump(config["split_data"], f) From 27ba67d5653d9abb0c4b554d4a775ce6ffc51809 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 17 Oct 2023 14:16:01 +0200 Subject: [PATCH 29/70] :art: increase fonts, improve plotting - fixed heatmap from -1 to 1 for correlations - shrink heatmap legend :bug: greater equal, not strictly greater for cutoff --- project/00_5_training_data_exploration.py | 44 ++++++++++++++++------- vaep/analyzers/analyzers.py | 2 +- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/project/00_5_training_data_exploration.py b/project/00_5_training_data_exploration.py index 95853d29d..ca1de1883 100644 --- a/project/00_5_training_data_exploration.py +++ b/project/00_5_training_data_exploration.py @@ -26,6 +26,7 @@ # %% from __future__ import annotations import json +import logging from pathlib import Path import numpy as np @@ -42,8 +43,9 @@ from vaep.analyzers import analyzers logger = vaep.logging.setup_nb_logger() +logging.getLogger('fontTools').setLevel(logging.WARNING) -matplotlib.rcParams.update({'font.size': 5, +matplotlib.rcParams.update({'font.size': 6, 'figure.figsize': [4.0, 2.0]}) @@ -189,7 +191,7 @@ def get_dynamic_range(min_max): # %% min_samples_per_feat = int(len(data) * COMPLETENESS_OVER_SAMPLES) print(f"{min_samples_per_feat = }") -mask = data.notna().sum(axis=0) > min_samples_per_feat +mask = data.notna().sum(axis=0) >= min_samples_per_feat print(f"drop = {(~mask).sum()} features") selected = data.loc[:, mask] selected.shape @@ -305,7 +307,7 @@ def get_dynamic_range(min_max): # %%time corr_lower_triangle = analyzers.corr_lower_triangle(data) fig, axes = analyzers.plot_corr_histogram(corr_lower_triangle, bins=40) -fname = FIGUREFOLDER / f'corr_histogram_feat.pdf' +fname = FIGUREFOLDER / 'corr_histogram_feat.pdf' files_out[fname.name] = fname vaep.savefig(fig, name=fname) @@ -317,7 +319,7 @@ def get_dynamic_range(min_max): cv = data.std() / data.mean() # biological coefficient of variation: standard deviation (variation) w.r.t mean ax = cv.hist(bins=30) -fname = FIGUREFOLDER / f'CV_histogram_features.pdf' +fname = FIGUREFOLDER / 'CV_histogram_features.pdf' files_out[fname.name] = fname vaep.savefig(ax.get_figure(), name=fname) @@ -328,7 +330,10 @@ def get_dynamic_range(min_max): # needs to deal with duplicates # notna = data.notna().T.drop_duplicates().T # get index and column names -cg = sns.clustermap(data.notna(), cbar_pos=None) +vaep.plotting.make_large_descriptors(8) +cg = sns.clustermap(data.notna(), + cbar_pos=None, + figsize=(8, 8)) ax = cg.ax_heatmap if PG_SEPARATOR is not None: _new_labels = [l.get_text().split(PG_SEPARATOR)[0] @@ -341,7 +346,8 @@ def get_dynamic_range(min_max): files_out[fname.name] = fname vaep.savefig(cg.fig, name=fname, - pdf=False) + pdf=False, + dpi=600) # %% [markdown] # based on cluster, plot heatmaps of features and samples @@ -351,10 +357,12 @@ def get_dynamic_range(min_max): cg.dendrogram_col.reordered_ind)) == data.shape # %% -vaep.plotting.make_large_descriptors(5) +vaep.plotting.make_large_descriptors(8) +fig, ax = plt.subplots(figsize=(4, 4)) ax = sns.heatmap( data.iloc[cg.dendrogram_row.reordered_ind, cg.dendrogram_col.reordered_ind], + ax=ax, ) only_every_x_ticks(ax, x=2) use_first_n_chars_in_labels(ax, x=SAMPLE_FIRST_N_CHARS) @@ -367,7 +375,7 @@ def get_dynamic_range(min_max): ax.set_yticks([]) fname = FIGUREFOLDER / 'heatmap_intensities_ordered_by_missing_pattern.png' files_out[fname.name] = fname -vaep.savefig(ax.get_figure(), name=fname, pdf=False) +vaep.savefig(fig, name=fname, pdf=False, dpi=600) # ax.get_figure().savefig(fname, dpi=300) # %% [markdown] @@ -378,6 +386,9 @@ def get_dynamic_range(min_max): ax = sns.heatmap( analyzers.corr_lower_triangle( data.iloc[:, cg.dendrogram_col.reordered_ind]), + vmin=-1, + vmax=1, + cbar_kws={'shrink': 0.75}, ax=ax, square=True, ) @@ -392,14 +403,19 @@ def get_dynamic_range(min_max): ax.set_yticks([]) fname = FIGUREFOLDER / 'heatmap_feature_correlation.png' files_out[fname.name] = fname -vaep.savefig(fig, name=fname, pdf=False) +vaep.savefig(fig, name=fname, pdf=False, dpi=600) +# %% +lower_corr = analyzers.corr_lower_triangle( + data.T.iloc[:, cg.dendrogram_row.reordered_ind]) # %% fig, ax = plt.subplots(figsize=(4, 4)) ax = sns.heatmap( - analyzers.corr_lower_triangle( - data.T.iloc[:, cg.dendrogram_row.reordered_ind]), + data=lower_corr, ax=ax, + vmin=-1, + vmax=1, + cbar_kws={'shrink': 0.75}, square=True, ) _ = only_every_x_ticks(ax, x=2) @@ -409,9 +425,10 @@ def get_dynamic_range(min_max): ax.set_yticks([]) fname = FIGUREFOLDER / 'heatmap_sample_correlation.png' files_out[fname.name] = fname -vaep.savefig(fig, name=fname, pdf=False) +vaep.savefig(fig, name=fname, pdf=False, dpi=600) # %% +vaep.plotting.make_large_descriptors(12) kwargs = dict() if NO_TICK_LABELS_ON_HEATMAP: kwargs['xticklabels'] = False @@ -446,6 +463,7 @@ def get_dynamic_range(min_max): sample_stats # %% +vaep.plotting.make_large_descriptors(8) fig_ident = sns.relplot( x='SampleID_int', y=COL_NO_IDENTIFIED, data=sample_stats) fig_ident.set_axis_labels('Sample ID', f'Frequency of identified {TYPE}') @@ -491,3 +509,5 @@ def get_dynamic_range(min_max): # %% files_out + +# %% diff --git a/vaep/analyzers/analyzers.py b/vaep/analyzers/analyzers.py index 364dbfef4..9c48d4ed8 100644 --- a/vaep/analyzers/analyzers.py +++ b/vaep/analyzers/analyzers.py @@ -428,7 +428,7 @@ def corr_lower_triangle(df): def plot_corr_histogram(corr_lower_triangle, bins=10): fig, axes = plt.subplots(ncols=2, gridspec_kw={"width_ratios": [ - 5, 1], "wspace": 0.2}, figsize=(10, 4)) + 5, 1], "wspace": 0.2}, figsize=(8, 4)) values = pd.Series(corr_lower_triangle.to_numpy().flatten()).dropna() ax = axes[0] ax = values.hist(ax=ax, bins=bins) From 225af4fa5ce86c86b8ac997bb28650230e97f27f Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Wed, 18 Oct 2023 19:08:36 +0200 Subject: [PATCH 30/70] :memo: update configs - managed to include more models for comparison --- .../evidence_N50/config.yaml | 29 +++++++++---------- .../peptides_N50/config.yaml | 22 +++++++------- .../proteinGroups/config.yaml | 24 +++++++-------- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/project/config/single_dev_dataset/evidence_N50/config.yaml b/project/config/single_dev_dataset/evidence_N50/config.yaml index 96cb77bfe..2884b973d 100644 --- a/project/config/single_dev_dataset/evidence_N50/config.yaml +++ b/project/config/single_dev_dataset/evidence_N50/config.yaml @@ -5,20 +5,20 @@ fn_rawfile_metadata: data/dev_datasets/df_intensities_evidence_long/metadata.csv file_format: csv models: - Median - - CF - - DAE - - VAE + - CF # 1min29s + - DAE # 2min36s + - VAE # 4min05s - KNN -NAGuideR_methods: - - BPCA + NAGuideR_methods: + - BPCA #27min - COLMEDIAN - - IMPSEQ + - IMPSEQ # 1min - IMPSEQROB - - IRM # stopped after 24h + - IRM # 12h00min - KNN_IMPUTE - - LLS # stopped after 24h - - MICE-CART - - MICE-NORM + # - LLS # error: out of memory + - MICE-CART # 2h39min + - MICE-NORM # 5min - MINDET - MINIMUM - MINPROB @@ -26,9 +26,8 @@ NAGuideR_methods: - MSIMPUTE - PI - QRILC - - RF # stopped after 24h + - RF # 3h44min - ROWMEDIAN - - SEQKNN - - SVDMETHOD - - TRKNN # stopped after 24h - - ZERO \ No newline at end of file + - SEQKNN # 24min + - SVDMETHOD # 1min + - TRKNN # 5h26min \ No newline at end of file diff --git a/project/config/single_dev_dataset/peptides_N50/config.yaml b/project/config/single_dev_dataset/peptides_N50/config.yaml index 8c335a367..612099b93 100644 --- a/project/config/single_dev_dataset/peptides_N50/config.yaml +++ b/project/config/single_dev_dataset/peptides_N50/config.yaml @@ -6,20 +6,20 @@ cuda: False file_format: csv models: - Median # maps to median on file system? - - CF - - DAE - - VAE + - CF # 3min + - DAE # 3min + - VAE # 5min - KNN NAGuideR_methods: - - BPCA + - BPCA #27min - COLMEDIAN - IMPSEQ - IMPSEQROB - - IRM + - IRM # 8h55min - KNN_IMPUTE - - LLS - - MICE-CART # stopped after 24h - - MICE-NORM # stopped after 24h + - LLS # 10h21min + - MICE-CART # 2h20min + - MICE-NORM # 4h25min - MINDET - MINIMUM - MINPROB @@ -27,9 +27,9 @@ NAGuideR_methods: - MSIMPUTE - PI - QRILC - - RF + - RF # 5h38min - ROWMEDIAN - - SEQKNN + - SEQKNN # 17min - SVDMETHOD - - TRKNN + - TRKNN #4h15min - ZERO \ No newline at end of file diff --git a/project/config/single_dev_dataset/proteinGroups/config.yaml b/project/config/single_dev_dataset/proteinGroups/config.yaml index a59a936f0..5b5bbcbcb 100644 --- a/project/config/single_dev_dataset/proteinGroups/config.yaml +++ b/project/config/single_dev_dataset/proteinGroups/config.yaml @@ -5,20 +5,20 @@ fn_rawfile_metadata: data/dev_datasets/df_intensities_proteinGroups_long/metadat cuda: False models: - Median - - CF - - DAE - - VAE + - CF # 2min + - DAE # 2min + - VAE # 2min - KNN NAGuideR_methods: - - BPCA + - BPCA #6h41min - COLMEDIAN - - IMPSEQ + - IMPSEQ # 1min - IMPSEQROB - - IRM + - IRM # 7h52min - KNN_IMPUTE - LLS - - MICE-CART # stopped after 24h - - MICE-NORM # stopped after 24h + # - MICE-CART # stopped after 24h + # - MICE-NORM # stopped after 24h - MINDET - MINIMUM - MINPROB @@ -26,9 +26,9 @@ NAGuideR_methods: - MSIMPUTE - PI - QRILC - - RF + - RF # 58min - ROWMEDIAN - - SEQKNN - - SVDMETHOD - - TRKNN + # - SEQKNN # Error in x[od, ismiss, drop = FALSE]: subscript out of bounds + - SVDMETHOD # 16min + - TRKNN # 5h38min - ZERO \ No newline at end of file From 45afa79834c70e4338020e4217726dbd5e2b04de Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Thu, 19 Oct 2023 18:09:02 +0200 Subject: [PATCH 31/70] :sparkles: exec status script, use conda, write configs - query torque cluster execution status changed, updated and moved - v2 of workflow now creates config files automatically which can still be used with version one - use pre-created conda environment with rule --- .../proteinGroups_N50/config_v2.yaml | 73 +++++++++++++++++++ .../proteinGroups_N50/split.yaml | 5 +- .../proteinGroups_N50/train_CF.yaml | 7 +- .../proteinGroups_N50/train_DAE.yaml | 8 +- .../proteinGroups_N50/train_KNN.yaml | 4 +- .../proteinGroups_N50/train_Median.yaml | 3 +- .../proteinGroups_N50/train_RSN.yaml | 1 - .../proteinGroups_N50/train_VAE.yaml | 10 +-- project/run_snakemake_cluster.sh | 10 ++- project/workflow/Snakefile | 4 + project/workflow/Snakefile_v2 | 18 +++-- project/workflow/bin/qsub-status.py | 26 +++++++ project/workflow/bin/qsub-status_v2.py | 26 +++++++ 13 files changed, 170 insertions(+), 25 deletions(-) create mode 100644 project/config/single_dev_dataset/proteinGroups_N50/config_v2.yaml delete mode 100644 project/config/single_dev_dataset/proteinGroups_N50/train_RSN.yaml create mode 100755 project/workflow/bin/qsub-status.py create mode 100755 project/workflow/bin/qsub-status_v2.py diff --git a/project/config/single_dev_dataset/proteinGroups_N50/config_v2.yaml b/project/config/single_dev_dataset/proteinGroups_N50/config_v2.yaml new file mode 100644 index 000000000..1b2ad226e --- /dev/null +++ b/project/config/single_dev_dataset/proteinGroups_N50/config_v2.yaml @@ -0,0 +1,73 @@ +config_split: config/single_dev_dataset/proteinGroups_N50/split.yaml # ! will be build +config_train: config/single_dev_dataset/proteinGroups_N50/train_{model}.yaml # ! will be build +folder_experiment: runs/dev_dataset_small/proteinGroups_N50_Snakefile_v2 +fn_rawfile_metadata: data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv +file_format: csv +split_data: + FN_INTENSITIES: data/dev_datasets/HeLa_6070/protein_groups_wide_N50.csv + fn_rawfile_metadata: data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv + sample_completeness: 0.5 + min_RT_time: 120 + column_names: + - Gene Names + index_col: 0 + meta_date_col: Content Creation Date +models: + - Median: + model: Median # needs to set at least one parameter + - CF: + model: CF + file_format: csv + latent_dim: 50 + batch_size: 4096 + epochs_max: 20 + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - DAE: + model: DAE + file_format: csv + latent_dim: 10 + batch_size: 10 + epochs_max: 200 + hidden_layers: "512" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - VAE: + model: VAE + file_format: csv + latent_dim: 25 + batch_size: 10 + epochs_max: 200 + hidden_layers: "512_256" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - KNN: + model: KNN + neighbors: 3 + file_format: csv +NAGuideR_methods: + - BPCA + - COLMEDIAN + - IMPSEQ + - IMPSEQROB + - IRM + - KNN_IMPUTE + - LLS + - MICE-CART + - MICE-NORM + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - PI + - QRILC + - RF + - ROWMEDIAN + - SEQKNN + - SVDMETHOD + - TRKNN + - ZERO diff --git a/project/config/single_dev_dataset/proteinGroups_N50/split.yaml b/project/config/single_dev_dataset/proteinGroups_N50/split.yaml index 32672a3ba..14ed36cdf 100644 --- a/project/config/single_dev_dataset/proteinGroups_N50/split.yaml +++ b/project/config/single_dev_dataset/proteinGroups_N50/split.yaml @@ -1,8 +1,9 @@ +# Build in Snakemake workflow FN_INTENSITIES: data/dev_datasets/HeLa_6070/protein_groups_wide_N50.csv fn_rawfile_metadata: data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv sample_completeness: 0.5 min_RT_time: 120 column_names: - - Gene Names +- Gene Names index_col: 0 -meta_date_col: Content Creation Date \ No newline at end of file +meta_date_col: Content Creation Date diff --git a/project/config/single_dev_dataset/proteinGroups_N50/train_CF.yaml b/project/config/single_dev_dataset/proteinGroups_N50/train_CF.yaml index 30f22595c..0b18de049 100644 --- a/project/config/single_dev_dataset/proteinGroups_N50/train_CF.yaml +++ b/project/config/single_dev_dataset/proteinGroups_N50/train_CF.yaml @@ -1,8 +1,9 @@ -folder_experiment: runs/example +# Build in Snakemake workflow +model: CF file_format: csv latent_dim: 50 batch_size: 4096 epochs_max: 20 sample_idx_position: 0 -cuda: False -save_pred_real_na: True \ No newline at end of file +cuda: false +save_pred_real_na: true diff --git a/project/config/single_dev_dataset/proteinGroups_N50/train_DAE.yaml b/project/config/single_dev_dataset/proteinGroups_N50/train_DAE.yaml index 7fe65c7ca..f3c6d66b0 100644 --- a/project/config/single_dev_dataset/proteinGroups_N50/train_DAE.yaml +++ b/project/config/single_dev_dataset/proteinGroups_N50/train_DAE.yaml @@ -1,8 +1,10 @@ +# Build in Snakemake workflow +model: DAE file_format: csv latent_dim: 10 batch_size: 10 epochs_max: 200 -hidden_layers: "512" +hidden_layers: '512' sample_idx_position: 0 -cuda: False -save_pred_real_na: True \ No newline at end of file +cuda: false +save_pred_real_na: true diff --git a/project/config/single_dev_dataset/proteinGroups_N50/train_KNN.yaml b/project/config/single_dev_dataset/proteinGroups_N50/train_KNN.yaml index 2d056f335..f5a6dd36e 100644 --- a/project/config/single_dev_dataset/proteinGroups_N50/train_KNN.yaml +++ b/project/config/single_dev_dataset/proteinGroups_N50/train_KNN.yaml @@ -1,2 +1,4 @@ +# Build in Snakemake workflow +model: KNN neighbors: 3 -file_format: csv \ No newline at end of file +file_format: csv diff --git a/project/config/single_dev_dataset/proteinGroups_N50/train_Median.yaml b/project/config/single_dev_dataset/proteinGroups_N50/train_Median.yaml index 745cca2c5..61c18b9d7 100644 --- a/project/config/single_dev_dataset/proteinGroups_N50/train_Median.yaml +++ b/project/config/single_dev_dataset/proteinGroups_N50/train_Median.yaml @@ -1 +1,2 @@ -file_format: csv \ No newline at end of file +# Build in Snakemake workflow +model: Median diff --git a/project/config/single_dev_dataset/proteinGroups_N50/train_RSN.yaml b/project/config/single_dev_dataset/proteinGroups_N50/train_RSN.yaml deleted file mode 100644 index dba9e23d8..000000000 --- a/project/config/single_dev_dataset/proteinGroups_N50/train_RSN.yaml +++ /dev/null @@ -1 +0,0 @@ -axis: 0 # per protein groups RSN \ No newline at end of file diff --git a/project/config/single_dev_dataset/proteinGroups_N50/train_VAE.yaml b/project/config/single_dev_dataset/proteinGroups_N50/train_VAE.yaml index bda8a795e..48ed2025d 100644 --- a/project/config/single_dev_dataset/proteinGroups_N50/train_VAE.yaml +++ b/project/config/single_dev_dataset/proteinGroups_N50/train_VAE.yaml @@ -1,10 +1,10 @@ -# models_training: -folder_experiment: runs/example +# Build in Snakemake workflow +model: VAE file_format: csv latent_dim: 25 batch_size: 10 epochs_max: 200 -hidden_layers: "512_256" +hidden_layers: '512_256' sample_idx_position: 0 -cuda: False -save_pred_real_na: True \ No newline at end of file +cuda: false +save_pred_real_na: true diff --git a/project/run_snakemake_cluster.sh b/project/run_snakemake_cluster.sh index b5b6dd13c..9838ff201 100644 --- a/project/run_snakemake_cluster.sh +++ b/project/run_snakemake_cluster.sh @@ -10,7 +10,7 @@ ### Email notification: a=aborts, b=begins, e=ends, n=no notifications #PBS -m ae -M henry.webel@cpr.ku.dk ### Number of nodes -#PBS -l nodes=1:ppn=1,mem=8gb +#PBS -l nodes=1:ppn=1,mem=16gb ### Requesting timeformat is ::: #PBS -l walltime=1:12:00:00 ### Forward all environment variables @@ -46,13 +46,15 @@ fi . ~/setup_conda.sh conda activate vaep -snakemake --jobs 10 -k -p --latency-wait 60 --rerun-incomplete \ +snakemake -s workflow/Snakefile --jobs 10 -k -p --latency-wait 60 --rerun-incomplete \ --configfile $configfile \ +--max-status-checks-per-second 0.5 \ +--use-conda \ --default-resources walltime=3600 \ --cluster "qsub -l walltime={resources.walltime},nodes=1:ppn={threads},mem={resources.mem_mb}mb"\ -" -W group_list=cpr_10006 -A cpr_10006 -V"\ +" -W group_list=cpr_10006 -A cpr_10006 "\ " -e {params.err} -o {params.out}"\ " -N ${prefix}.{params.name}" \ ---cluster-status "python ../workflows/maxquant/qsub-status.py" && +--cluster-status "python workflow/bin/qsub-status_v2.py" && echo "done" || echo "failed" diff --git a/project/workflow/Snakefile b/project/workflow/Snakefile index c3489e842..f68f37f3b 100644 --- a/project/workflow/Snakefile +++ b/project/workflow/Snakefile @@ -120,6 +120,8 @@ rule train_NAGuideR_model: folder_experiment="{folder_experiment}", method="{method}", name="{method}", + conda: + "vaep" shell: "papermill {input.nb} {output.nb}" " -r train_split {input.train_split}" @@ -166,6 +168,8 @@ rule train_models: err="{folder_experiment}/01_1_train_{model}.e", out="{folder_experiment}/01_1_train_{model}.o", name="{model}", + conda: + "vaep" shell: "papermill {input.nb} {output.nb}" " -f {input.configfile}" diff --git a/project/workflow/Snakefile_v2 b/project/workflow/Snakefile_v2 index 6dfb4e28a..1e6b1cc78 100644 --- a/project/workflow/Snakefile_v2 +++ b/project/workflow/Snakefile_v2 @@ -4,7 +4,7 @@ Document how all the notebooks for a single experiment are connected. from snakemake.logging import logger -configfile: "config/single_dev_dataset/proteinGroups_N50/config.yaml" +configfile: "config/single_dev_dataset/proteinGroups_N50/config_v2.yaml" MAX_WALLTIME = "24:00:00" @@ -22,6 +22,8 @@ localrules: transform_NAGuideR_predictions, transform_data_to_wide_format, create_splits, + dump_train_config, + dump_split_config, rule all: @@ -134,6 +136,8 @@ rule train_NAGuideR_model: folder_experiment="{folder_experiment}", method="{method}", name="{method}", + conda: + "vaep" shell: "papermill {input.nb} {output.nb}" " -r train_split {input.train_split}" @@ -182,6 +186,8 @@ rule train_models: err="{folder_experiment}/01_1_train_{model}.e", out="{folder_experiment}/01_1_train_{model}.o", name="{model}", + conda: + "vaep" shell: "papermill {input.nb} {output.nb}" " -f {input.configfile}" @@ -202,7 +208,8 @@ rule dump_train_config: import yaml with open(output.configfile, "w") as f: - yaml.dump(model_configs[wildcards.model], f) + f.write("# Build in Snakemake workflow\n") + yaml.dump(model_configs[wildcards.model], f, sort_keys=False) ########################################################################################## @@ -214,7 +221,7 @@ nb_stem = "01_0_split_data" rule create_splits: input: nb=f"{nb_stem}.ipynb", - configfile=f"{folder_experiment}/{nb_stem}.yaml", + configfile=config["config_split"], #f"{folder_experiment}/{nb_stem}.yaml", output: train_split="{folder_experiment}/data/train_X.csv", nb="{folder_experiment}" f"/{nb_stem}.ipynb", @@ -237,9 +244,10 @@ rule create_splits: rule dump_split_config: output: - configfile=f"{folder_experiment}/{nb_stem}.yaml", + configfile=config["config_split"], #f"{folder_experiment}/{nb_stem}.yaml", run: import yaml with open(output.configfile, "w") as f: - yaml.dump(config["split_data"], f) + f.write("# Build in Snakemake workflow\n") + yaml.dump(config["split_data"], f, sort_keys=False) diff --git a/project/workflow/bin/qsub-status.py b/project/workflow/bin/qsub-status.py new file mode 100755 index 000000000..acdd47554 --- /dev/null +++ b/project/workflow/bin/qsub-status.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# https://github.com/Snakemake-Profiles/pbs-torque/blob/master/%7B%7Bcookiecutter.profile_name%7D%7D/pbs-status.py +import sys +import subprocess +import xml.etree.cElementTree as ET + +jobid = sys.argv[1] + +try: + res = subprocess.run("qstat -f -x {}".format(jobid), check=True, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) + + xmldoc = ET.ElementTree(ET.fromstring(res.stdout.decode())).getroot() + job_state = xmldoc.findall('.//job_state')[0].text + + if job_state == "C": + exit_status = xmldoc.findall('.//exit_status')[0].text + if exit_status == '0': + print("success") + else: + print("failed") + else: + print("running") + +except (subprocess.CalledProcessError, IndexError, KeyboardInterrupt) as e: + print("failed") \ No newline at end of file diff --git a/project/workflow/bin/qsub-status_v2.py b/project/workflow/bin/qsub-status_v2.py new file mode 100755 index 000000000..4f67d1a02 --- /dev/null +++ b/project/workflow/bin/qsub-status_v2.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# https://github.com/Snakemake-Profiles/pbs-torque/blob/master/%7B%7Bcookiecutter.profile_name%7D%7D/pbs-status.py +import sys +import subprocess + +jobid = sys.argv[1] + +try: + # ! do net query full information + qstat = subprocess.run("qstat {}".format(jobid), check=True, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) + res = qstat.stdout.decode(errors='ignore') + + if "C" in res: + full = subprocess.run("qstat -f -x {}".format(jobid), check=True, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) + full = full.stdout.decode(errors='ignore') + if "0" in full: + print("success") + else: + print("failed") + else: + print("running") + +except (subprocess.CalledProcessError, IndexError, KeyboardInterrupt) as e: + print("failed") \ No newline at end of file From 47824ce8d4abf7582da0d6f6acf3b12b21f1ac9f Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Fri, 20 Oct 2023 16:25:55 +0200 Subject: [PATCH 32/70] :art: Snakefile_v2 ready as new default - can create the configs needed for current workflow in Snakefile Next: Test and swap + document --- project/workflow/Snakefile_v2 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/project/workflow/Snakefile_v2 b/project/workflow/Snakefile_v2 index 1e6b1cc78..08220f227 100644 --- a/project/workflow/Snakefile_v2 +++ b/project/workflow/Snakefile_v2 @@ -10,9 +10,10 @@ configfile: "config/single_dev_dataset/proteinGroups_N50/config_v2.yaml" MAX_WALLTIME = "24:00:00" # Thinnode resources sharing: 40 cores and 196 GB RAM (minus 2GB for snakemake) # JOB_RAM_MB = int(204_800 / 40 * config['THREATS_MQ']) -JOB_RAM_MB = "4gb" +JOB_RAM_MB = "8gb" folder_experiment = config["folder_experiment"] logger.info(f"{folder_experiment = }") +logger.info(f"{config = }") # local rules are excuted in the process (job) running snakemake @@ -180,6 +181,9 @@ rule train_models: pred="{folder_experiment}/preds/pred_test_{model}.csv", benchmark: "{folder_experiment}/01_1_train_{model}.tsv" + resources: + mem_mb=JOB_RAM_MB, + walltime=MAX_WALLTIME, params: folder_experiment="{folder_experiment}", meta_data=config["fn_rawfile_metadata"], From 464cc1cfd0859876f9311dbc627a4e738dbaa5a4 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Fri, 20 Oct 2023 16:31:32 +0200 Subject: [PATCH 33/70] :truck: group grid search configs --- project/config/{ => grid_search_large_data}/config_grid.yaml | 2 +- .../{ => grid_search_large_data}/config_grid_small.yaml | 2 +- project/config/grid_search_large_data/evidence_split.yaml | 5 +++++ project/config/grid_search_large_data/peptides_split.yaml | 5 +++++ .../config/grid_search_large_data/proteinGroups_split.yaml | 3 +++ project/workflow/Snakefile_grid.smk | 4 +++- 6 files changed, 18 insertions(+), 3 deletions(-) rename project/config/{ => grid_search_large_data}/config_grid.yaml (91%) rename project/config/{ => grid_search_large_data}/config_grid_small.yaml (89%) create mode 100644 project/config/grid_search_large_data/evidence_split.yaml create mode 100644 project/config/grid_search_large_data/peptides_split.yaml create mode 100644 project/config/grid_search_large_data/proteinGroups_split.yaml diff --git a/project/config/config_grid.yaml b/project/config/grid_search_large_data/config_grid.yaml similarity index 91% rename from project/config/config_grid.yaml rename to project/config/grid_search_large_data/config_grid.yaml index f1e9531e6..1523a47df 100644 --- a/project/config/config_grid.yaml +++ b/project/config/grid_search_large_data/config_grid.yaml @@ -29,7 +29,7 @@ levels: - proteinGroups - peptides - evidence -config_split: 'config/single_dev_dataset/{level}/split.yaml' +config_split: config/grid_search_large_data/{level}_split.yaml file_format: csv config_train: 'placeholder.yaml' name_template: run/LD_{latent_dim}_E_{epochs_max} diff --git a/project/config/config_grid_small.yaml b/project/config/grid_search_large_data/config_grid_small.yaml similarity index 89% rename from project/config/config_grid_small.yaml rename to project/config/grid_search_large_data/config_grid_small.yaml index 4c0bb90ee..c29a09dbd 100644 --- a/project/config/config_grid_small.yaml +++ b/project/config/grid_search_large_data/config_grid_small.yaml @@ -16,7 +16,7 @@ levels: - proteinGroups - peptides # - evidence -config_split: 'config/single_dev_dataset/{level}/split.yaml' +config_split: 'config/grid_search_large_data/{level}_split.yaml' file_format: csv config_train: 'placeholder.yaml' cuda: False diff --git a/project/config/grid_search_large_data/evidence_split.yaml b/project/config/grid_search_large_data/evidence_split.yaml new file mode 100644 index 000000000..e766c0b62 --- /dev/null +++ b/project/config/grid_search_large_data/evidence_split.yaml @@ -0,0 +1,5 @@ +FN_INTENSITIES: data/dev_datasets/df_intensities_evidence_long/Q_Exactive_HF_X_Orbitrap_6070.pkl +fn_rawfile_metadata: data/dev_datasets/df_intensities_evidence_long/metadata.csv +sample_completeness: 0.5 +min_RT_time: 120 +column_names: null \ No newline at end of file diff --git a/project/config/grid_search_large_data/peptides_split.yaml b/project/config/grid_search_large_data/peptides_split.yaml new file mode 100644 index 000000000..732957cb3 --- /dev/null +++ b/project/config/grid_search_large_data/peptides_split.yaml @@ -0,0 +1,5 @@ +FN_INTENSITIES: data/dev_datasets/df_intensities_peptides_long/Q_Exactive_HF_X_Orbitrap_6070.pkl +fn_rawfile_metadata: data/dev_datasets/df_intensities_peptides_long/metadata.csv +sample_completeness: 0.5 +min_RT_time: 120 +column_names: null \ No newline at end of file diff --git a/project/config/grid_search_large_data/proteinGroups_split.yaml b/project/config/grid_search_large_data/proteinGroups_split.yaml new file mode 100644 index 000000000..675f1b785 --- /dev/null +++ b/project/config/grid_search_large_data/proteinGroups_split.yaml @@ -0,0 +1,3 @@ +FN_INTENSITIES: data/dev_datasets/df_intensities_proteinGroups_long/Q_Exactive_HF_X_Orbitrap_6070.pkl +sample_completeness: 0.5 +min_RT_time: 120 \ No newline at end of file diff --git a/project/workflow/Snakefile_grid.smk b/project/workflow/Snakefile_grid.smk index 4d4cfc148..c7809a83b 100644 --- a/project/workflow/Snakefile_grid.smk +++ b/project/workflow/Snakefile_grid.smk @@ -4,7 +4,7 @@ from snakemake.utils import min_version min_version("6.0") -configfile: "config/config_grid_small.yaml" +configfile: "config/grid_search_large_data/config_grid_small.yaml" # prefix: "grid_search" # could be used to redirect all outputs @@ -229,6 +229,8 @@ rule train_ae_models: params: folder_dataset=f"{root_model}/{run_id_template}", # model_key="HL_{hidden_layers}_LD_{hidden_layers}", # ToDo + # add log + # https://snakemake.readthedocs.io/en/stable/snakefiles/rules.html#log-files threads: 10 shell: "papermill {input.nb} {output.nb}" From 345d256da7cc8862cbb80b29fea768f4e53b2268 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Tue, 31 Oct 2023 16:18:33 +0100 Subject: [PATCH 34/70] :art: format workflows --- project/workflow/Snakefile_ald_comparison.smk | 45 ++++++++++--------- .../Snakefile_ald_comparison_repeated.smk | 7 ++- .../Snakefile_best_across_datasets.smk | 1 + .../Snakefile_best_repeated_split.smk | 8 +++- .../Snakefile_best_repeated_train.smk | 4 +- project/workflow/Snakefile_grid.smk | 6 +-- project/workflow/Snakefile_small_N.smk | 10 +++-- project/workflow/TestNotebooks.smk | 26 +---------- 8 files changed, 50 insertions(+), 57 deletions(-) diff --git a/project/workflow/Snakefile_ald_comparison.smk b/project/workflow/Snakefile_ald_comparison.smk index ecfc10e5d..0b79e9c1b 100644 --- a/project/workflow/Snakefile_ald_comparison.smk +++ b/project/workflow/Snakefile_ald_comparison.smk @@ -22,7 +22,8 @@ target_cutoff = dict(kleiner="2") target = "kleiner" -all_methods = [config["baseline"], 'None', *config["methods"]] +all_methods = [config["baseline"], "None", *config["methods"]] + wildcard_constraints: target=target, @@ -34,13 +35,14 @@ wildcard_constraints: rule all: input: expand( - out_folder + 'diff_analysis_compare_DA.xlsx', + out_folder + "diff_analysis_compare_DA.xlsx", target=target, - out_folder=config["out_folder"],), + out_folder=config["out_folder"], + ), expand( [ out_folder_two_methods_cp + "diff_analysis_comparision_2_{model}.pdf", - out_folder_two_methods_cp + "mrmr_feat_by_model.xlsx" + out_folder_two_methods_cp + "mrmr_feat_by_model.xlsx", ], target=[target], baseline=config["baseline"], @@ -48,21 +50,23 @@ rule all: out_folder=config["out_folder"], ), + ########################################################################################## # Create plots for featues where decisions between model differ (if computed) nb = "10_4_ald_compare_single_pg.ipynb" + rule plot_intensities_for_diverging_results: input: - expand(folder_experiment + "/preds/pred_real_na_{method}.csv", - method=[ - config["baseline"], - *config["methods"]],), expand( - [ - out_folder + "scores/diff_analysis_scores_{model}.pkl", - ], + folder_experiment + "/preds/pred_real_na_{method}.csv", + method=[config["baseline"], *config["methods"]], + ), + expand( + [ + out_folder + "scores/diff_analysis_scores_{model}.pkl", + ], target=[target], baseline=config["baseline"], model=all_methods, @@ -71,19 +75,19 @@ rule plot_intensities_for_diverging_results: nb=nb, fn_clinical_data="data/ALD_study/processed/ald_metadata_cli.csv", output: - diff_da = out_folder + 'diff_analysis_compare_DA.xlsx', - qvalues = out_folder + 'qvalues_target.pkl', - nb=out_folder + nb + diff_da=out_folder + "diff_analysis_compare_DA.xlsx", + qvalues=out_folder + "qvalues_target.pkl", + nb=out_folder + nb, params: baseline=config["baseline"], cutoff=lambda wildcards: config["cutoffs"][wildcards.target], make_plots=config["make_plots"], - ref_method_score = config['ref_method_score'] # None, + ref_method_score=config["ref_method_score"], # None, shell: "papermill {input.nb} {output.nb}" f" -r folder_experiment {folder_experiment}" " -r target {wildcards.target}" - " -r baseline {params.baseline}" # not yet used + " -r baseline {params.baseline}" " -r out_folder {wildcards.out_folder}" " -p cutoff_target {params.cutoff}" " -p make_plots {params.make_plots}" @@ -119,16 +123,18 @@ rule ml_comparison: " -r fn_clinical_data {input.fn_clinical_data}" " && jupyter nbconvert --to html {output.nb}" + ########################################################################################## # basemethod vs other methods nb = "10_2_ald_compare_methods.ipynb" nb_stem = "10_2_ald_compare_methods" + rule compare_diff_analysis: input: nb=nb, score_base=out_folder + "scores/diff_analysis_scores_{baseline}.pkl", - score_model=out_folder + "scores/diff_analysis_scores_{model}.pkl" + score_model=out_folder + "scores/diff_analysis_scores_{model}.pkl", output: nb=out_folder_two_methods_cp + nb, figure=out_folder_two_methods_cp + "diff_analysis_comparision_2_{model}.pdf", @@ -136,7 +142,7 @@ rule compare_diff_analysis: disease_ontology=lambda wildcards: config["disease_ontology"][wildcards.target], annotaitons_gene_col=config["annotaitons_gene_col"], benchmark: - out_folder_two_methods_cp + f"{nb_stem}.tsv", + out_folder_two_methods_cp + f"{nb_stem}.tsv" shell: "papermill {input.nb} {output.nb}" f" -r folder_experiment {folder_experiment}" @@ -172,6 +178,3 @@ rule differential_analysis: " -r model_key {wildcards.model}" " -r out_folder {wildcards.out_folder}" " && jupyter nbconvert --to html {output.nb}" - - - diff --git a/project/workflow/Snakefile_ald_comparison_repeated.smk b/project/workflow/Snakefile_ald_comparison_repeated.smk index 38e45ee70..87498d9a6 100644 --- a/project/workflow/Snakefile_ald_comparison_repeated.smk +++ b/project/workflow/Snakefile_ald_comparison_repeated.smk @@ -12,19 +12,21 @@ sub_folder = "diff_analysis" N = 10 make_plots = False + rule all: input: f"{folder_experiment}/agg_differences_compared.xlsx", + rule compare_repetitions: input: - qvalues = expand( + qvalues=expand( f"{out_folder}/qvalues_target.pkl", target=target, sub_folder=sub_folder, run=range(N), ), - equality_rejected_target = expand( + equality_rejected_target=expand( f"{out_folder}/equality_rejected_target.pkl", target=target, sub_folder=sub_folder, @@ -39,6 +41,7 @@ rule compare_repetitions: notebook: "../10_5_comp_diff_analysis_repetitions.ipynb" + rule run_comparison_workflow: input: f"{folder_run}/figures/errors_binned_by_int_test.pdf", diff --git a/project/workflow/Snakefile_best_across_datasets.smk b/project/workflow/Snakefile_best_across_datasets.smk index 0850bb919..ea208a1c4 100644 --- a/project/workflow/Snakefile_best_across_datasets.smk +++ b/project/workflow/Snakefile_best_across_datasets.smk @@ -55,6 +55,7 @@ rule collect_metrics: REPITITION_NAME = params.repitition_name + # key fully specified in path def key_from_fname(fname): key = (fname.parents[2].name, fname.parents[1].name) diff --git a/project/workflow/Snakefile_best_repeated_split.smk b/project/workflow/Snakefile_best_repeated_split.smk index 44f37f860..279cc031f 100644 --- a/project/workflow/Snakefile_best_repeated_split.smk +++ b/project/workflow/Snakefile_best_repeated_split.smk @@ -10,8 +10,10 @@ config["folder_experiment"] = folder_experiment MODELS = ["DAE", "VAE", "CF"] + wildcard_constraints: - model="|".join(MODELS) + model="|".join(MODELS), + rule all: input: @@ -58,6 +60,7 @@ rule collect_metrics: nb = "01_0_split_data.ipynb" + rule create_splits: input: nb=nb, @@ -69,7 +72,7 @@ rule create_splits: folder_experiment=f"{folder_experiment}", meta_data=config["fn_rawfile_metadata"], file_format=config["file_format"], - random_state="{repeat}" + random_state="{repeat}", shell: "papermill {input.nb} {output.nb}" " -f {input.configfile}" @@ -79,6 +82,7 @@ rule create_splits: " -p random_state {params.random_state}" " && jupyter nbconvert --to html {output.nb}" + rule train_models: input: nb="01_1_train_{model}.ipynb", diff --git a/project/workflow/Snakefile_best_repeated_train.smk b/project/workflow/Snakefile_best_repeated_train.smk index 7e6f26a58..a76c89351 100644 --- a/project/workflow/Snakefile_best_repeated_train.smk +++ b/project/workflow/Snakefile_best_repeated_train.smk @@ -10,6 +10,7 @@ config["folder_experiment"] = folder_experiment MODELS = ["DAE", "VAE", "CF"] + rule all: input: f"{config['folder']}/model_performance_repeated_runs.pdf", @@ -53,9 +54,9 @@ rule collect_metrics: "notebooks/best_repeated_train_collect_metrics.ipynb" - nb = "01_0_split_data.ipynb" + rule create_splits: input: nb=nb, @@ -75,6 +76,7 @@ rule create_splits: " -r file_format {params.file_format}" " && jupyter nbconvert --to html {output.nb}" + rule train_models: input: nb="01_1_train_{model}.ipynb", diff --git a/project/workflow/Snakefile_grid.smk b/project/workflow/Snakefile_grid.smk index c7809a83b..299a512ea 100644 --- a/project/workflow/Snakefile_grid.smk +++ b/project/workflow/Snakefile_grid.smk @@ -6,6 +6,7 @@ min_version("6.0") configfile: "config/grid_search_large_data/config_grid_small.yaml" + # prefix: "grid_search" # could be used to redirect all outputs @@ -236,10 +237,10 @@ rule train_ae_models: "papermill {input.nb} {output.nb}" " -f {input.configfile}" " -r folder_experiment {params.folder_dataset}" - # " -r model_key {params.model_key}" " && jupyter nbconvert --to html {output.nb}" + rule build_train_config_ae: output: config_train=f"{root_model}/{run_id_template}/config_nb_train.yaml", @@ -311,7 +312,7 @@ rule train_CF_model: metric=f"{root_model}/{run_id_template}/metrics_{_model}.json", config=f"{root_model}/{run_id_template}/model_config_{_model}.yaml", benchmark: - f"{root_model}/{run_id_template}/01_1_train_{_model}.tsv", + f"{root_model}/{run_id_template}/01_1_train_{_model}.tsv" threads: 10 params: folder_experiment=f"{root_model}/{run_id_template}", @@ -326,7 +327,6 @@ rule train_CF_model: " && jupyter nbconvert --to html {output.nb}" - rule build_train_config_collab: output: config_nb_train=f"{root_model}/{run_id_template}/config_nb_train_CF.yaml", diff --git a/project/workflow/Snakefile_small_N.smk b/project/workflow/Snakefile_small_N.smk index 01aab082d..398dfb349 100644 --- a/project/workflow/Snakefile_small_N.smk +++ b/project/workflow/Snakefile_small_N.smk @@ -8,6 +8,7 @@ min_version("6.0") configfile: "config/single_dev_dataset/proteinGroups_N50/config.yaml" + # prefix: "grid_search" # could be used to redirect all outputs @@ -20,6 +21,7 @@ module single_experiment: config: config + root_experiment = Path(config["folder_experiment"]) # runs/dev_dataset_small/proteinGroups_N50 @@ -27,12 +29,14 @@ folder_experiment = config["folder_experiment"][:-2] + "{N}" config["folder_experiment"] = folder_experiment - logger.info(f"{folder_experiment = }") logger.info(f"{root_experiment = }") + rule all: - input: combined_xlsx=f"{root_experiment.parent}/{root_experiment.name}_all_small.xlsx" + input: + combined_xlsx=f"{root_experiment.parent}/{root_experiment.name}_all_small.xlsx", + rule combine_result_tables: input: @@ -65,7 +69,6 @@ MODELS = single_experiment.MODELS # logger.info(f"{config['NAGuideR_methods'] = }") - # # MODELS = config["models"].copy() # # # ! needed to run NAGuideR methods, but needs to be switched off for comparison nb # # # ? how is the original config imported here? @@ -75,6 +78,7 @@ MODELS = single_experiment.MODELS nb = "01_2_performance_plots.ipynb" + use rule comparison from single_experiment as adapted_comparison with: input: nb=nb, diff --git a/project/workflow/TestNotebooks.smk b/project/workflow/TestNotebooks.smk index 1abd20b1e..9d8399827 100644 --- a/project/workflow/TestNotebooks.smk +++ b/project/workflow/TestNotebooks.smk @@ -1,33 +1,9 @@ notebookes = [ - "misc_FASTA_data_agg_by_gene.ipynb", - "misc_FASTA_tryptic_digest.ipynb", - # "2_clustering_proteins.ipynb", # Reference Annelaura - "erda_data_available.ipynb", - "misc_data_exploration_peptides.ipynb", - "misc_data_exploration_proteins.ipynb", - "00_0_hela_metadata_rawfiles.ipynb", - "00_1_hela_MQ_summaries.ipynb", - "00_2_hela_all_raw_files.ipynb", - "misc_protein_support.ipynb", - "00_5_training_data_exploration.ipynb", - "00_4_development_dataset_support.ipynb", - "01_0_split_data.ipynb", - "14_experiment_03_dataloaders.ipynb", - "14_experiment_03_dataset.ipynb", - # "02_3_grid_search_analysis.ipynb", # needs parametrization for testing - "14_experiment_03_latent_space_analysis.ipynb", "misc_embeddings.ipynb", "misc_illustrations.ipynb", "misc_pytorch_fastai_dataloaders.ipynb", "misc_pytorch_fastai_dataset.ipynb", - "erda_00_maxquant_file_reader.ipynb", - "erda_01_mq_aggregate_summaries.ipynb", - "erda_02_mq_count_peptides.ipynb", - # "erda_10_training_data.ipynb", - # "erda_11_select_training_data.ipynb", - # "erda_12_explore_raw_MQ_data.ipynb", - # "VAEP_POC.ipynb", # to discard - # "misc_id_mapper.ipynb", # to discard + "misc_sampling_in_pandas.ipynb" ] From 43aa9a1fe81749013a5d217c648a4a22c6f121a1 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Tue, 31 Oct 2023 16:18:57 +0100 Subject: [PATCH 35/70] :fire: move to hela_qc_mnt_data project -> Snakefile in project folder --- project/workflow/Snakemake_project.smk | 113 ------------------------- 1 file changed, 113 deletions(-) delete mode 100644 project/workflow/Snakemake_project.smk diff --git a/project/workflow/Snakemake_project.smk b/project/workflow/Snakemake_project.smk deleted file mode 100644 index 87058d84e..000000000 --- a/project/workflow/Snakemake_project.smk +++ /dev/null @@ -1,113 +0,0 @@ -"""Workflow to produce global analysis for the project.""" -nb_outfolder = "runs" - -DATASETS=[ "df_intensities_proteinGroups_long", - "df_intensities_peptides_long", - "df_intensities_evidence_long" - ] - -OUT_INFO = "dataset_info" - -rule all: - input: - "data/files_per_instrument.yaml", # nested: model, attribute, serial number - "data/files_selected_metadata.csv", - "data/files_selected_per_instrument.yaml", - "data/files_selected_per_instrument_counts.csv", # counts - f'{nb_outfolder}/{"00_2_hela_all_raw_files.ipynb"}', - "data/samples_selected.yaml", - expand( - "data/single_datasets/{dataset}/{OUT_INFO}.json", - dataset=DATASETS, - OUT_INFO=OUT_INFO, - ), - - -nb = "00_2_hela_all_raw_files.ipynb" - - -rule metadata: - input: - nb=nb, - # meta='../workflows/metadata/rawfile_metadata.json', - meta="data/all_raw_files_dump_2021_10_29.txt", - summaries="data/processed/all_summaries.json", - intensities="data/df_intensities_N07285_M01000", # csv - output: - nb=f"{nb_outfolder}/{nb}", - # # final config - # {'FN_ALL_RAW_FILES': 'data/all_raw_files_dump_2021_10_29.txt', # input - # 'FN_ALL_SUMMARIES': 'data/processed/all_summaries.json', # input - # 'FN_ALL_RAW_FILES_UNIQUE': 'data/all_raw_files_dump_2021_10_29_unique_N50521_M00003.csv', - # 'FN_ALL_RAW_FILES_DUPLICATED': 'data/all_raw_files_dump_2021_10_29_duplicated.txt', - # 'raw_file_overview': 'Figures/raw_file_overview.pdf', - # 'fname_1000_most_common_peptides': 'data/df_intensities_N07285_M01000', - # 'figure_1': 'Figures/figure_1.pdf', - # 'remote_files': 'data/remote_files.yaml'} - shell: - "papermill {input.nb} {output.nb}" - " -p FN_ALL_RAW_FILES {input.meta}" - " -p FN_ALL_SUMMARIES {input.summaries}" - " -p FN_PEPTIDE_INTENSITIES {input.intensities}" - " && jupyter nbconvert --to html {output.nb}" - - -nb = "00_1_hela_MQ_summaries.ipynb" - - -rule summaries: - input: - nb=nb, - summaries="data/processed/all_summaries.json", - output: - nb=f"{nb_outfolder}/{nb}", - selected="data/samples_selected.yaml", - shell: - "papermill {input.nb} {output.nb}" - " -r FN_ALL_SUMMARIES {input.summaries}" - " && jupyter nbconvert --to html {output.nb}" - - -nb = "00_0_hela_metadata_rawfiles.ipynb" - - -rule metadata_rawfiles: - input: - "data/rawfile_metadata.csv", - "data/samples_selected.yaml", - nb=nb, - output: - "data/files_per_instrument.yaml", # nested: model, attribute, serial number - "data/files_selected_metadata.csv", - "data/files_selected_per_instrument.yaml", - "data/files_selected_per_instrument_counts.csv", # counts - nb=f"{nb_outfolder}/{nb}", - shell: - "papermill {input.nb} {output.nb}" - " && jupyter nbconvert --to html {output.nb}" # run with defaults - - - -nb='00_3_hela_development_dataset_splitting.ipynb' -outfolder=f'dev_datasets' -ROOT_DUMPS = "C:/Users/kzl465/OneDrive - University of Copenhagen/vaep/project/data" - - -rule split_data: - input: - nb=nb, - data=f"{ROOT_DUMPS}/{{dataset}}.pkl", - output: - nb=f"data/dev_datasets/{{dataset}}/{nb}", - json=f'data/dev_datasets/{{dataset}}/{OUT_INFO}.xlsx' - params: - folder_datasets="single_datasets/{dataset}", - shell: - # papermill parameters with whitespaces > - "papermill {input.nb} {output.nb}" - ' -r DUMP "{input.data}" ' - " -r FILE_EXT pkl" - " -r FOLDER_DATASETS {params.folder_datasets}" - ' -r SAMPLE_ID "Sample ID" ' - f" -r OUT_INFO {OUT_INFO} " - " && jupyter nbconvert --to html {output.nb}" From a358d78fdfb8a6bab2949583c1adb2e6ddd439ee Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Tue, 31 Oct 2023 16:20:56 +0100 Subject: [PATCH 36/70] :memo: add "version" to config file - document relationship between updated and old workflow's configuration files (-> how to specify models and parameters) --- .../plasma/proteinGroups_80%_dataset/config.yaml | 1 + project/config/permuted_dataset/config.yaml | 1 + project/config/single_dev_dataset/evidence/config.yaml | 1 + project/config/single_dev_dataset/peptides/config.yaml | 1 + project/config/single_dev_dataset/proteinGroups/config.yaml | 1 + .../single_dev_dataset/proteinGroups_N50/config_v2.yaml | 1 + project/workflow/Snakefile_v2 | 4 ++-- 7 files changed, 8 insertions(+), 2 deletions(-) diff --git a/project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/config.yaml b/project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/config.yaml index 91db84805..75bde92ba 100644 --- a/project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/config.yaml +++ b/project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v1 config_split: config/appl_ald_data/plasma/proteinGroups_80%_dataset/split.yaml config_train: config/appl_ald_data/plasma/proteinGroups/train_{model}.yaml folder_experiment: runs/appl_ald_data/plasma/proteinGroups_80%_dataset diff --git a/project/config/permuted_dataset/config.yaml b/project/config/permuted_dataset/config.yaml index 7c36c7999..3d5657868 100644 --- a/project/config/permuted_dataset/config.yaml +++ b/project/config/permuted_dataset/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v1 # fit permuted data to the same model as the original data config_split: config/permuted_dataset/split.yaml # proteinGroups config_train: config/single_dev_dataset/proteinGroups/train_{model}.yaml diff --git a/project/config/single_dev_dataset/evidence/config.yaml b/project/config/single_dev_dataset/evidence/config.yaml index e92b8d64f..fb86e8d9a 100644 --- a/project/config/single_dev_dataset/evidence/config.yaml +++ b/project/config/single_dev_dataset/evidence/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v1 config_split: config/single_dev_dataset/evidence/split.yaml config_train: config/single_dev_dataset/evidence/train_{model}.yaml folder_experiment: runs/dev_dataset_large/evidence diff --git a/project/config/single_dev_dataset/peptides/config.yaml b/project/config/single_dev_dataset/peptides/config.yaml index 3bd4be650..caf67d87e 100644 --- a/project/config/single_dev_dataset/peptides/config.yaml +++ b/project/config/single_dev_dataset/peptides/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v1 config_split: config/single_dev_dataset/peptides/split.yaml config_train: config/single_dev_dataset/peptides/train_{model}.yaml folder_experiment: runs/dev_dataset_large/peptides diff --git a/project/config/single_dev_dataset/proteinGroups/config.yaml b/project/config/single_dev_dataset/proteinGroups/config.yaml index 5b5bbcbcb..6b9baadf7 100644 --- a/project/config/single_dev_dataset/proteinGroups/config.yaml +++ b/project/config/single_dev_dataset/proteinGroups/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v1 config_split: config/single_dev_dataset/proteinGroups/split.yaml config_train: config/single_dev_dataset/proteinGroups/train_{model}.yaml folder_experiment: runs/dev_dataset_large/proteinGroups diff --git a/project/config/single_dev_dataset/proteinGroups_N50/config_v2.yaml b/project/config/single_dev_dataset/proteinGroups_N50/config_v2.yaml index 1b2ad226e..51b501a3b 100644 --- a/project/config/single_dev_dataset/proteinGroups_N50/config_v2.yaml +++ b/project/config/single_dev_dataset/proteinGroups_N50/config_v2.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v2 config_split: config/single_dev_dataset/proteinGroups_N50/split.yaml # ! will be build config_train: config/single_dev_dataset/proteinGroups_N50/train_{model}.yaml # ! will be build folder_experiment: runs/dev_dataset_small/proteinGroups_N50_Snakefile_v2 diff --git a/project/workflow/Snakefile_v2 b/project/workflow/Snakefile_v2 index 08220f227..90807c8ac 100644 --- a/project/workflow/Snakefile_v2 +++ b/project/workflow/Snakefile_v2 @@ -225,7 +225,7 @@ nb_stem = "01_0_split_data" rule create_splits: input: nb=f"{nb_stem}.ipynb", - configfile=config["config_split"], #f"{folder_experiment}/{nb_stem}.yaml", + configfile=config["config_split"], output: train_split="{folder_experiment}/data/train_X.csv", nb="{folder_experiment}" f"/{nb_stem}.ipynb", @@ -248,7 +248,7 @@ rule create_splits: rule dump_split_config: output: - configfile=config["config_split"], #f"{folder_experiment}/{nb_stem}.yaml", + configfile=config["config_split"], run: import yaml From 801c8233916bfebf2f8a7d9c064416def808f5fe Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Tue, 31 Oct 2023 16:23:18 +0100 Subject: [PATCH 37/70] :truck: move shell scripts to folder bin --- project/{ => bin}/run_snakemake.sh | 33 ++++++---------------- project/{ => bin}/run_snakemake_cluster.sh | 12 ++++---- 2 files changed, 14 insertions(+), 31 deletions(-) rename project/{ => bin}/run_snakemake.sh (56%) rename project/{ => bin}/run_snakemake_cluster.sh (85%) diff --git a/project/run_snakemake.sh b/project/bin/run_snakemake.sh similarity index 56% rename from project/run_snakemake.sh rename to project/bin/run_snakemake.sh index 83b5aa572..e01a13255 100644 --- a/project/run_snakemake.sh +++ b/project/bin/run_snakemake.sh @@ -3,14 +3,14 @@ ### Account information #PBS -W group_list=cpr_10006 -A cpr_10006 ### Job name (comment out the next line to get the name of the script used as the job name) -#PBS -N snakemake +#PBS -N sn_grid ### Output files (comment out the next 2 lines to get the job name used instead) -#PBS -e ${PBS_JOBNAME}.${PBS_JOBID}.e -#PBS -o ${PBS_JOBNAME}.${PBS_JOBID}.o +#PBS -e qsub_logs${PBS_JOBNAME}.${PBS_JOBID}.e +#PBS -o qsub_logs${PBS_JOBNAME}.${PBS_JOBID}.o ### Email notification: a=aborts, b=begins, e=ends, n=no notifications #PBS -m ae -M henry.webel@cpr.ku.dk ### Number of nodes -### other: #PBS -l nodes=1:ppn=40:gpus=1 +### other: #PBS -l nodes=1:ppn=20:mem:40g #PBS -l nodes=1:ppn=40 ### Requesting timeformat is ::: #PBS -l walltime=1:00:00:00 @@ -18,34 +18,17 @@ ### if authentification is done using pw in the environment #PBS -V -module load tools git/2.15.0 -module load anaconda3/2021.11 - -# >>> conda initialize >>> -# !! Contents within this block are managed by 'conda init' !! -__conda_setup="$('/services/tools/anaconda3/2021.11/bin/conda' 'shell.bash' 'hook' 2> /dev/null)" -if [ $? -eq 0 ]; then - eval "$__conda_setup" -else - if [ -f "/services/tools/anaconda3/2021.11/etc/profile.d/conda.sh" ]; then - . "/services/tools/anaconda3/2021.11/etc/profile.d/conda.sh" - else - export PATH="/services/tools/anaconda3/2021.11/bin:$PATH" - fi -fi -unset __conda_setup -# <<< conda initialize <<< - # Go to the directory from where the job was submitted (initial directory is $HOME) echo Working directory is $PBS_O_WORKDIR cd $PBS_O_WORKDIR - +# start_conda +. ~/setup_conda.sh conda activate vaep # try to influence how many jobs are run in parallel in one job training a model -export MKL_NUM_THREADS=10 +export MKL_NUM_THREADS=5 -snakemake --snakefile workflow/Snakefile_grid.smk --rerun-incomplete -f -j 4 -c 40 +snakemake --snakefile workflow/Snakefile_grid.smk --rerun-incomplete -f -j 4 -c 20 diff --git a/project/run_snakemake_cluster.sh b/project/bin/run_snakemake_cluster.sh similarity index 85% rename from project/run_snakemake_cluster.sh rename to project/bin/run_snakemake_cluster.sh index 9838ff201..2b2bb7894 100644 --- a/project/run_snakemake_cluster.sh +++ b/project/bin/run_snakemake_cluster.sh @@ -5,15 +5,14 @@ ### Job name (comment out the next line to get the name of the script used as the job name) #PBS -N snakemake ### Output files (comment out the next 2 lines to get the job name used instead) -#PBS -e ${PBS_JOBNAME}.${PBS_JOBID}.e -#PBS -o ${PBS_JOBNAME}.${PBS_JOBID}.o +#PBS -e qsub_logs/${PBS_JOBNAME}.${PBS_JOBID}.e +#PBS -o qsub_logs/${PBS_JOBNAME}.${PBS_JOBID}.o ### Email notification: a=aborts, b=begins, e=ends, n=no notifications #PBS -m ae -M henry.webel@cpr.ku.dk ### Number of nodes -#PBS -l nodes=1:ppn=1,mem=16gb +#PBS -l nodes=1:ppn=2,mem=16gb ### Requesting timeformat is ::: #PBS -l walltime=1:12:00:00 -### Forward all environment variables @@ -46,9 +45,10 @@ fi . ~/setup_conda.sh conda activate vaep -snakemake -s workflow/Snakefile --jobs 10 -k -p --latency-wait 60 --rerun-incomplete \ +snakemake -s workflow/Snakefile_v2 --jobs 10 -k -p -c2 --latency-wait 60 --rerun-incomplete \ --configfile $configfile \ ---max-status-checks-per-second 0.5 \ +--max-status-checks-per-second 0.1 \ +--max-jobs-per-second 1 \ --use-conda \ --default-resources walltime=3600 \ --cluster "qsub -l walltime={resources.walltime},nodes=1:ppn={threads},mem={resources.mem_mb}mb"\ From 51b57db2573259082b38ca91304c18941596cc86 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Wed, 1 Nov 2023 21:07:34 +0100 Subject: [PATCH 38/70] :memo::bug: Test execution of "misc_*" notebooks - `testNotebooks.smk` can do it. - set kernel to current environement (generic "Python 3") --- project/misc_embeddings.ipynb | 4 +- project/misc_embeddings.py | 39 ++ project/misc_illustrations.ipynb | 6 +- project/misc_illustrations.py | 8 +- project/misc_json_formats.ipynb | 4 +- project/misc_json_formats.py | 112 +++++ project/misc_pytorch_fastai_dataloaders.ipynb | 49 ++- project/misc_pytorch_fastai_dataloaders.py | 416 ++++++++++++++++++ project/misc_pytorch_fastai_dataset.ipynb | 14 +- project/misc_pytorch_fastai_dataset.py | 211 +++++++++ project/misc_sampling_in_pandas.ipynb | 4 +- project/misc_sampling_in_pandas.py | 132 ++++++ project/workflow/README.md | 6 +- 13 files changed, 961 insertions(+), 44 deletions(-) create mode 100644 project/misc_embeddings.py create mode 100644 project/misc_json_formats.py create mode 100644 project/misc_pytorch_fastai_dataloaders.py create mode 100644 project/misc_pytorch_fastai_dataset.py create mode 100644 project/misc_sampling_in_pandas.py diff --git a/project/misc_embeddings.ipynb b/project/misc_embeddings.ipynb index 97d53839e..36c60b2dc 100644 --- a/project/misc_embeddings.ipynb +++ b/project/misc_embeddings.ipynb @@ -138,9 +138,9 @@ ], "metadata": { "kernelspec": { - "display_name": "vaep", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "vaep" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/project/misc_embeddings.py b/project/misc_embeddings.py new file mode 100644 index 000000000..fcbc27eb4 --- /dev/null +++ b/project/misc_embeddings.py @@ -0,0 +1,39 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.15.2 +# kernelspec: +# display_name: Python 3 (ipykernel) +# language: python +# name: python3 +# --- + +# %% [markdown] +# ## Understanding Embeddings + +# %% +from fastai.tabular.all import * +from fastai.collab import * + +# %% +# Embedding? + +# %% +Embedding + +# %% +e = Embedding(100, 10) + +# %% +idx = torch.tensor([1, 3]) +e(idx).detach().numpy() + +# %% +idx = torch.tensor([1, 2]) +e(idx).detach().numpy() + +# %% diff --git a/project/misc_illustrations.ipynb b/project/misc_illustrations.ipynb index eef8b6065..02012ad42 100644 --- a/project/misc_illustrations.ipynb +++ b/project/misc_illustrations.ipynb @@ -96,9 +96,9 @@ "outputs": [], "source": [ "\n", - "fig.savefig(cfg.FIGUREFOLDER / 'illustration_normal_imputation')\n", - "fig.savefig(cfg.FIGUREFOLDER / 'illustration_normal_imputation.pdf')\n", - "fig.savefig(cfg.FIGUREFOLDER / 'illustration_normal_imputation_highres', dpi=600)" + "fig.savefig(FIGUREFOLDER / 'illustration_normal_imputation')\n", + "fig.savefig(FIGUREFOLDER / 'illustration_normal_imputation.pdf')\n", + "fig.savefig(FIGUREFOLDER / 'illustration_normal_imputation_highres', dpi=600)" ] }, { diff --git a/project/misc_illustrations.py b/project/misc_illustrations.py index 4f4690e02..cdfd362fb 100644 --- a/project/misc_illustrations.py +++ b/project/misc_illustrations.py @@ -5,7 +5,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.15.0 +# jupytext_version: 1.15.2 # kernelspec: # display_name: Python 3 # language: python @@ -67,9 +67,9 @@ fig.tight_layout() # %% -fig.savefig(cfg.FIGUREFOLDER / 'illustration_normal_imputation') -fig.savefig(cfg.FIGUREFOLDER / 'illustration_normal_imputation.pdf') -fig.savefig(cfg.FIGUREFOLDER / 'illustration_normal_imputation_highres', dpi=600) +fig.savefig(FIGUREFOLDER / 'illustration_normal_imputation') +fig.savefig(FIGUREFOLDER / 'illustration_normal_imputation.pdf') +fig.savefig(FIGUREFOLDER / 'illustration_normal_imputation_highres', dpi=600) # %% [markdown] diff --git a/project/misc_json_formats.ipynb b/project/misc_json_formats.ipynb index 81f6d10ee..b503d2a04 100644 --- a/project/misc_json_formats.ipynb +++ b/project/misc_json_formats.ipynb @@ -226,9 +226,9 @@ ], "metadata": { "kernelspec": { - "display_name": "vaep", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "vaep" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/project/misc_json_formats.py b/project/misc_json_formats.py new file mode 100644 index 000000000..b589ea91c --- /dev/null +++ b/project/misc_json_formats.py @@ -0,0 +1,112 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.15.2 +# kernelspec: +# display_name: Python 3 (ipykernel) +# language: python +# name: python3 +# --- + +# %% [markdown] +# # Json Formats +# +# - object is loaded with the correct conversions (but this is re-computed) +# - can shared information be saved as "meta" information? +# +# - [`pd.json_normalize`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.json_normalize.html) should be able to efficiently combine information + +# %% +import pandas as pd +from vaep.io.data_objects import MqAllSummaries +from vaep.pandas import get_unique_non_unique_columns + +mq_all_summaries = MqAllSummaries() + +# %% [markdown] +# ## summaries.json + +# %% [markdown] +# ### Table format with schema + +# %% +# json format with categories +columns = get_unique_non_unique_columns(mq_all_summaries.df) +columns.unique[:2] + +# %% +mq_all_summaries.df[columns.unique[:3]].dtypes + +# %% +type(mq_all_summaries.df.iloc[0,3]) + +# %% +meta = mq_all_summaries.df[columns.unique].iloc[0].to_json(indent=4, orient='table') +# print(meta) + +# %% +pd.read_json(meta, orient='table').T.convert_dtypes() + +# %% +pd.read_json(meta, orient='table') # produce errors when having int columns has NaN + +# %% +pd.options.display.max_columns = len(columns.non_unique) +# mq_all_summaries.df[columns.non_unique] + +# %% +data = mq_all_summaries.df[columns.non_unique].iloc[0:3].to_json() +data = pd.read_json(data) +data + +# %% +mq_all_summaries.fp_summaries.parent / mq_all_summaries.fp_summaries.stem / '_meta.json' + +# %% +meta = mq_all_summaries.df[columns.unique].iloc[0].to_json(indent=4) +meta = pd.read_json(meta, typ='series') +meta + +# %% +for col, value in meta.items(): + data[col] = value + +# %% +data + +# %% [markdown] +# ## Table schema bug +# +# - filed bug report on pandas [#40255](https://github.com/pandas-dev/pandas/issues/40255) + +# %% +pd.show_versions() + +# %% +pd.__version__ + +# %% +import traceback +import pandas +data = {'A' : [1, 2, 2, pd.NA, 4, 8, 8, 8, 8, 9], + 'B': [pd.NA] * 10} +data = pd.DataFrame(data) +data = data.astype(pd.Int64Dtype()) # in my example I get this from data.convert_dtypes() +data_json = data.to_json(orient='table', indent=4) +try: + pd.read_json(data_json, orient='table') #ValueError: Cannot convert non-finite values (NA or inf) to integer +except ValueError as e: + print(e) + traceback.print_exc() + +# %% +print(data.to_string()) + +# %% +N = 3 +meta = mq_all_summaries.df[columns.unique[:N]].iloc[0:2].reset_index(drop=True) +meta.to_dict() diff --git a/project/misc_pytorch_fastai_dataloaders.ipynb b/project/misc_pytorch_fastai_dataloaders.ipynb index fe025a473..71ab4b573 100644 --- a/project/misc_pytorch_fastai_dataloaders.ipynb +++ b/project/misc_pytorch_fastai_dataloaders.ipynb @@ -62,7 +62,8 @@ " def setups(self, to):\n", " store_attr(but='to', na_dict={n:self.fill_strategy(to[n], self.fill_vals[n])\n", " for n in to.conts.keys()})\n", - " self.fill_strategy = self.fill_strategy.__name__\n" + " self.fill_strategy = self.fill_strategy.__name__\n", + "\n" ] }, { @@ -97,11 +98,11 @@ "X_test = create_df(int(N*0.1), M, prop_na=.1, start_idx=len(X))\n", "\n", "data = DataSplits(train_X=X.loc[X.index.difference(idx_val)],\n", - " val_X=X.loc[idx_val],\n", - " test_X=X_test,\n", + " val_y=X.loc[idx_val],\n", + " test_y=X_test,\n", " is_wide_format=True)\n", "\n", - "data.val_X.loc[data.val_X.isna().any(axis=1), data.val_X.isna().any(axis=0)]" + "data.val_y.loc[data.val_y.isna().any(axis=1), data.val_y.isna().any(axis=0)]" ] }, { @@ -167,9 +168,9 @@ "metadata": {}, "outputs": [], "source": [ - "X = data.train_X.append(data.val_X)\n", + "X = data.train_X.append(data.val_y)\n", "\n", - "splits = X.index.get_indexer(data.val_X.index) # In Tabular iloc is used, not loc for splitting\n", + "splits = X.index.get_indexer(data.val_y.index) # In Tabular iloc is used, not loc for splitting\n", "splits = IndexSplitter(splits)(X) # splits is are to list of integer indicies (for iloc)\n", " \n", "procs = [Normalize, FillMissingKeepAll]\n", @@ -304,8 +305,8 @@ "metadata": {}, "outputs": [], "source": [ - "# test_ds = TabularPandas(data.test_X, cont_names=data.test_X.columns.to_list())\n", - "dl_test = dls.test_dl(data.test_X.copy())\n", + "# test_ds = TabularPandas(data.test_y, cont_names=data.test_y.columns.to_list())\n", + "dl_test = dls.test_dl(data.test_y.copy())\n", "dl_test.xs.head()" ] }, @@ -334,7 +335,7 @@ "metadata": {}, "outputs": [], "source": [ - "to_test = TabularPandas(data.test_X.copy(), procs=None, cont_names=data.test_X.columns.to_list(), splits=None, do_setup=True)\n", + "to_test = TabularPandas(data.test_y.copy(), procs=None, cont_names=data.test_y.columns.to_list(), splits=None, do_setup=True)\n", "_ = procs(to_test) # inplace operation\n", "to_test.items.head()" ] @@ -346,7 +347,7 @@ "metadata": {}, "outputs": [], "source": [ - "data.test_X.head()" + "data.test_y.head()" ] }, { @@ -422,7 +423,7 @@ "outputs": [], "source": [ "train_ds = DatasetWithMaskAndNoTarget(df=data.train_X)\n", - "valid_ds = DatasetWithMaskAndNoTarget(df=data.val_X)\n", + "valid_ds = DatasetWithMaskAndNoTarget(df=data.val_y)\n", "train_ds[-1]" ] }, @@ -481,7 +482,7 @@ " \n", "o_tf_norm = Normalize()\n", "o_tf_norm.setup(data.train_X)\n", - "o_tf_norm(data.val_X.head()) # apply this manueally to each dataset" + "o_tf_norm(data.val_y.head()) # apply this manueally to each dataset" ] }, { @@ -502,7 +503,7 @@ "outputs": [], "source": [ "train_ds = DatasetWithMaskAndNoTarget(df=o_tf_norm(data.train_X))\n", - "valid_ds = DatasetWithMaskAndNoTarget(df=o_tf_norm(data.val_X))\n", + "valid_ds = DatasetWithMaskAndNoTarget(df=o_tf_norm(data.val_y))\n", "\n", "dls = DataLoaders.from_dsets(\n", " train_ds,\n", @@ -526,9 +527,9 @@ "\n", "assert (dls.valid.one_batch()[1] < 0.0).any(), \"Normalization did not work.\"\n", "with pytest.raises(AttributeError):\n", - " DatasetWithMaskAndNoTarget(df=data.val_X, transformer=o_tf_norm)\n", + " DatasetWithMaskAndNoTarget(df=data.val_y, transformer=o_tf_norm)\n", " \n", - "# assert_array_almost_equal(DatasetWithMaskAndNoTarget(df=data.val_X, transformer=o_tf_norm)[0][1], DatasetWithMaskAndNoTarget(df=o_tf_norm(data.val_X))[0][1])\n", + "# assert_array_almost_equal(DatasetWithMaskAndNoTarget(df=data.val_y, transformer=o_tf_norm)[0][1], DatasetWithMaskAndNoTarget(df=o_tf_norm(data.val_y))[0][1])\n", "# with pytest.raises(AttributeError):\n", "# valid_ds.inverse_transform(dls.valid.one_batch()[1])" ] @@ -576,7 +577,7 @@ "metadata": {}, "outputs": [], "source": [ - "valid_ds = DatasetWithMaskAndNoTarget(data.val_X, dae_transforms)\n", + "valid_ds = DatasetWithMaskAndNoTarget(data.val_y, dae_transforms)\n", "valid_ds[:4]" ] }, @@ -588,7 +589,7 @@ "outputs": [], "source": [ "from vaep.io.dataloaders import get_dls\n", - "dls = get_dls(data.train_X, data.val_X, dae_transforms, bs=4) \n", + "dls = get_dls(data.train_X, data.val_y, dae_transforms, bs=4) \n", "dls.valid.one_batch()" ] }, @@ -600,7 +601,7 @@ "outputs": [], "source": [ "test_dl = DataLoader(\n", - " dataset=DatasetWithMaskAndNoTarget(data.test_X, dae_transforms),\n", + " dataset=DatasetWithMaskAndNoTarget(data.test_y, dae_transforms),\n", " shuffle=False,\n", " bs=4)\n", "test_dl.one_batch()" @@ -623,7 +624,7 @@ "metadata": {}, "outputs": [], "source": [ - "data.test_X.head(4)" + "data.test_y.head(4)" ] }, { @@ -671,8 +672,8 @@ " range(len(data.train_X)),\n", " DatasetTransform(data.train_X))\n", "valid_tl = TfmdLists(\n", - " range(len(data.val_X)),\n", - " DatasetTransform(data.val_X))\n", + " range(len(data.val_y)),\n", + " DatasetTransform(data.val_y))\n", "\n", "dls = DataLoaders.from_dsets(train_tl, valid_tl,\n", "# after_item=[Normalize],\n", @@ -707,7 +708,7 @@ "_transform_fct = scaler.transform\n", "\n", "train_ds = DatasetWithMaskAndNoTarget(df=_transform_fct(data.train_X))\n", - "valid_ds = DatasetWithMaskAndNoTarget(df=_transform_fct(data.val_X))\n", + "valid_ds = DatasetWithMaskAndNoTarget(df=_transform_fct(data.val_y))\n", "\n", "dls = DataLoaders.from_dsets(train_ds, valid_ds,\n", " bs=4)\n", @@ -733,9 +734,9 @@ ], "metadata": { "kernelspec": { - "display_name": "vaep", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "vaep" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/project/misc_pytorch_fastai_dataloaders.py b/project/misc_pytorch_fastai_dataloaders.py new file mode 100644 index 000000000..0dddfeef6 --- /dev/null +++ b/project/misc_pytorch_fastai_dataloaders.py @@ -0,0 +1,416 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.15.2 +# kernelspec: +# display_name: Python 3 (ipykernel) +# language: python +# name: python3 +# --- + +# %% [markdown] +# # `DataLoaders` for feeding data into models + +# %% +import numpy as np +import pandas as pd + +import fastai +from fastai.tabular.core import Normalize +from fastai.tabular.core import FillMissing +from fastai.tabular.core import TabularPandas +from fastai.tabular.core import IndexSplitter +# make DataLoaders.test_dl work for DataFrames as test_items: + +# from fastai.tabular.all import * +from fastai.tabular.all import TabularDataLoaders +from fastcore.transform import Pipeline + +import torch + +from vaep.logging import setup_nb_logger +setup_nb_logger() + +from vaep.io.datasplits import DataSplits +from vaep.io.datasets import DatasetWithMaskAndNoTarget, to_tensor +from vaep.transform import VaepPipeline +from vaep.models import ae +from vaep.utils import create_random_df + +np.random.seed(42) +print(f"fastai version: {fastai.__version__}") +print(f"torch version: {torch.__version__}") + +# %% +from fastcore.transform import Pipeline + +from fastcore.basics import store_attr +class FillMissingKeepAll(FillMissing): + """Replacement for `FillMissing` including also non-missing features + in the training data which might be missing in the validation or test data. + """ + def setups(self, to): + store_attr(but='to', na_dict={n:self.fill_strategy(to[n], self.fill_vals[n]) + for n in to.conts.keys()}) + self.fill_strategy = self.fill_strategy.__name__ + + + +# %% [markdown] +# Create data +# +# - train data without missings +# - validation and test data with missings +# +# Could be adapted to have more or less missing in training, validation or test data. Choosen as in current version the validation data cannot contain features with missing values which were not missing in the training data. + +# %% +N, M = 150, 15 + +create_df = create_random_df + +X = create_df(N, M) +X = X.append(create_df(int(N*0.3), M, prop_na=.1, start_idx=len(X))) + +idx_val = X.index[N:] # RandomSplitter could be used, but used to show IndexSplitter usage with Tabular + +X_test = create_df(int(N*0.1), M, prop_na=.1, start_idx=len(X)) + +data = DataSplits(train_X=X.loc[X.index.difference(idx_val)], + val_y=X.loc[idx_val], + test_y=X_test, + is_wide_format=True) + +data.val_y.loc[data.val_y.isna().any(axis=1), data.val_y.isna().any(axis=0)] + +# %% [markdown] +# ## Collab + +# %% + +# %% [markdown] +# ## Denoising Autoencoder + +# %% [markdown] +# ### DataSet `Tabular` +# +# - `fastai.tabular.core.Tabular` +# +# +# Adding procs / transforms manually +# +# ```python +# cont_names = list(splits.train_X.columns) +# to = TabularPandas(splits.train_X, cont_names=cont_names, do_setup=False) +# +# tf_norm = NORMALIZER() +# tf_fillna = FillMissing(add_col=True) +# +# _ = tf_norm.setups(to) # returns to +# _ = tf_fillna.setup(to) +# ``` +# +# No added in a manuel pipeline. See [opened issue](https://github.com/fastai/fastai/issues/3530) on `Tabular` behaviour. +# Setting transformation (procs) in the constructor is somehow not persistent, although very similar code is called. +# +# ``` +# # not entirely empty, but to.procs.fs needs to be populated +# type(to.procs), to.procs.fs # __call__, setup, decode, fs +# ``` + +# %% +X = data.train_X.append(data.val_y) + +splits = X.index.get_indexer(data.val_y.index) # In Tabular iloc is used, not loc for splitting +splits = IndexSplitter(splits)(X) # splits is are to list of integer indicies (for iloc) + +procs = [Normalize, FillMissingKeepAll] + +to = TabularPandas(X, procs=procs, cont_names=X.columns.to_list(), splits=splits) # to = tabular object + +print("Tabular object:", type(to)) +to.items.head() + +# %% [markdown] +# Test data with procs + +# %% +procs = to.procs +procs.fs + +# %% [markdown] +# Let's format this to see what it does +# +# ```python +# # (#2) +# [ +# FillMissingKeepAll -- +# {'fill_strategy': , +# 'add_col': True, +# 'fill_vals': defaultdict(, {'feat_00': 0, 'feat_01': 0, 'feat_02': 0, ..., 'feat_14': 13.972452} +# }: +# encodes: (object,object) -> encodes +# decodes: , +# Normalize -- +# {'mean': None, 'std': None, 'axes': (0, 2, 3), +# 'means': {'feat_00': 14.982738, 'feat_01': 13.158741, 'feat_02': 14.800485, ..., 'feat_14': 8.372757} +# }: +# encodes: (TensorImage,object) -> encodes +# (Tabular,object) -> encodes +# decodes: (TensorImage,object) -> decodes +# (Tabular,object) -> decodes +# ] +# +# ``` + +# %% +procs + +# %% +# Check behaviour +procs.encodes + +# %% [markdown] +# #### DataLoader + +# %% +dls = to.dataloaders(bs=4) +dls.show_batch() + +# %% +dls.one_batch() + +# %% +[x.dtype for x in dls.one_batch()] + +# %% [markdown] +# #### transfrom test data using `DataLoaders.test_dl` + +# %% +# test_ds = TabularPandas(data.test_y, cont_names=data.test_y.columns.to_list()) +dl_test = dls.test_dl(data.test_y.copy()) +dl_test.xs.head() + +# %% +dl_test.show_batch() + +# %% [markdown] +# #### Transform test data manuelly + +# %% +to_test = TabularPandas(data.test_y.copy(), procs=None, cont_names=data.test_y.columns.to_list(), splits=None, do_setup=True) +_ = procs(to_test) # inplace operation +to_test.items.head() + +# %% +data.test_y.head() + +# %% [markdown] +# #### Feeding one batch to the model + +# %% +cats, conts, ys = dls.one_batch() + +# %% +model = ae.Autoencoder(n_features=M, n_neurons=int( + M/2), last_decoder_activation=None, dim_latent=10) +model + +# %% [markdown] +# The forward pass just uses the conts features + +# %% +model(conts) + +# %% [markdown] +# #### target +# - missing puzzle piece is to have a `callable` y-block which transforms part of the input. In principle it could be the same as the continous features + +# %% [markdown] +# ### PyTorch Dataset + +# %% +train_ds = DatasetWithMaskAndNoTarget(df=data.train_X) +valid_ds = DatasetWithMaskAndNoTarget(df=data.val_y) +train_ds[-1] + +# %% [markdown] +# #### DataLoaders + +# %% +from fastai.data.core import DataLoaders + +dls = DataLoaders.from_dsets(train_ds, valid_ds, + bs=4) + +dls.valid.one_batch() + +# %% [markdown] +# #### DataLoaders with Normalization fastai Transform + +# %% +from fastai.tabular.all import * +class Normalize(Transform): + def setup(self, array): + self.mean = array.mean() # this assumes tensor, numpy arrays and alike + # should be applied along axis 0 (over the samples) + self.std = array.std() # ddof=0 in scikit-learn + + def encodes(self, x): # -> torch.Tensor: # with type annotation this throws an error + x_enc = (x - self.mean) / self.std + return x_enc + + def decodes(self, x_enc:torch.tensor) -> torch.Tensor: + x = (self.std * x_enc) + self.mean + return x + +o_tf_norm = Normalize() +o_tf_norm.setup(data.train_X) +o_tf_norm(data.val_y.head()) # apply this manueally to each dataset + +# %% +o_tf_norm.encodes # object= everything + +# %% +train_ds = DatasetWithMaskAndNoTarget(df=o_tf_norm(data.train_X)) +valid_ds = DatasetWithMaskAndNoTarget(df=o_tf_norm(data.val_y)) + +dls = DataLoaders.from_dsets( + train_ds, + valid_ds, + # tfms=[o_tf_norm], + # after_batch=[o_tf_norm], + bs=4) + +dls.valid.one_batch() + +# %% +import pytest +from numpy.testing import assert_array_almost_equal, assert_array_less + +assert (dls.valid.one_batch()[1] < 0.0).any(), "Normalization did not work." +with pytest.raises(AttributeError): + DatasetWithMaskAndNoTarget(df=data.val_y, transformer=o_tf_norm) + +# assert_array_almost_equal(DatasetWithMaskAndNoTarget(df=data.val_y, transformer=o_tf_norm)[0][1], DatasetWithMaskAndNoTarget(df=o_tf_norm(data.val_y))[0][1]) +# with pytest.raises(AttributeError): +# valid_ds.inverse_transform(dls.valid.one_batch()[1]) + +# %% [markdown] +# #### DataLoaders with Normalization sklearn transform +# +# - solve transformation problem by composition +# - inverse transform only used for + +# %% +import sklearn +# from sklearn import preprocessing +from sklearn.impute import SimpleImputer +from sklearn.preprocessing import StandardScaler + +import vaep +# import importlib; importlib.reload(vaep); importlib.reload(vaep.transform) + +dae_default_pipeline = sklearn.pipeline.Pipeline( + [ + ('normalize', StandardScaler()), + ('impute', SimpleImputer(add_indicator=False)) + ]) +# new procs, transform equal encode, inverse_transform equals decode +dae_transforms = VaepPipeline( + df_train=data.train_X, encode=dae_default_pipeline, decode=['normalize']) + +# %% +valid_ds = DatasetWithMaskAndNoTarget(data.val_y, dae_transforms) +valid_ds[:4] + +# %% +from vaep.io.dataloaders import get_dls +dls = get_dls(data.train_X, data.val_y, dae_transforms, bs=4) +dls.valid.one_batch() + +# %% +test_dl = DataLoader( + dataset=DatasetWithMaskAndNoTarget(data.test_y, dae_transforms), + shuffle=False, + bs=4) +test_dl.one_batch() + +# %% +dae_transforms.inverse_transform(test_dl.one_batch()[1]) # here the missings are not replaced + +# %% +data.test_y.head(4) + +# %% [markdown] +# ### FastAi Transfrom (as Dataset) +# +# - adding `Transforms` not possible, I openend a [discussion](https://forums.fast.ai/t/correct-output-type-for-tensor-created-from-dataframe-custom-new-task-tutorial/92564) + +# %% +from typing import Tuple +from fastai.tabular.all import * +# from fastai.torch_core import TensorBase + + +class DatasetTransform(Transform): + def __init__(self, df: pd.DataFrame): + if not issubclass(type(df), pd.DataFrame): + raise ValueError( + f'please pass a pandas DataFrame, not: {type(df) = }') + self.mask_obs = df.isna() # .astype('uint8') # in case 0,1 is preferred + self.data = df + + def encodes(self, idx): # -> Tuple[torch.Tensor, torch.Tensor]: # annotation is interpreted + mask = self.mask_obs.iloc[idx] + data = self.data.iloc[idx] + # return (self.to_tensor(mask), self.to_tensor(data)) + # return (Tensor(mask), Tensor(data)) + return (tensor(data), tensor(mask)) #TabData, TabMask + + def to_tensor(self, s: pd.Series) -> torch.Tensor: + return torch.from_numpy(s.values) + + +train_tl = TfmdLists( + range(len(data.train_X)), + DatasetTransform(data.train_X)) +valid_tl = TfmdLists( + range(len(data.val_y)), + DatasetTransform(data.val_y)) + +dls = DataLoaders.from_dsets(train_tl, valid_tl, +# after_item=[Normalize], +# after_batch=[Normalize], + bs=4) +print(f"\n{DatasetTransform.encodes = }") +dls.one_batch() + +# %% [markdown] +# ## Variational Autoencoder + +# %% +from vaep.transform import MinMaxScaler + +args_vae = {} +args_vae['SCALER'] = MinMaxScaler +# select initial data: transformed vs not log transformed +scaler = args_vae['SCALER']().fit(data.train_X) + +_transform_fct = scaler.transform + +train_ds = DatasetWithMaskAndNoTarget(df=_transform_fct(data.train_X)) +valid_ds = DatasetWithMaskAndNoTarget(df=_transform_fct(data.val_y)) + +dls = DataLoaders.from_dsets(train_ds, valid_ds, + bs=4) +dls.one_batch() + +# %% [markdown] +# ## FastAi version + +# %% diff --git a/project/misc_pytorch_fastai_dataset.ipynb b/project/misc_pytorch_fastai_dataset.ipynb index c7404c1b3..622f2ac4d 100644 --- a/project/misc_pytorch_fastai_dataset.ipynb +++ b/project/misc_pytorch_fastai_dataset.ipynb @@ -251,9 +251,9 @@ "from vaep.io.datasplits import long_format\n", "\n", "\n", - "\n", + "data = pd.DataFrame(data)\n", + "data.index.name, data.columns.name = ('Sample ID', 'peptide')\n", "df_long = long_format(pd.DataFrame(data))\n", - "df_long.index.names = ('Sample ID', 'peptide')\n", "df_long.reset_index(inplace=True)\n", "df_long.head()" ] @@ -397,10 +397,12 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ - "next(iter(dls.dataset))\n" + "next(iter(dls.dataset))" ] }, { @@ -416,9 +418,9 @@ "hash": "ca718f398b3a596c3df6787ca2afa269ec54c58eb9478d66aeb41db8e6cb8262" }, "kernelspec": { - "display_name": "vaep", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "vaep" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/project/misc_pytorch_fastai_dataset.py b/project/misc_pytorch_fastai_dataset.py new file mode 100644 index 000000000..fb9317e17 --- /dev/null +++ b/project/misc_pytorch_fastai_dataset.py @@ -0,0 +1,211 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.15.2 +# kernelspec: +# display_name: Python 3 (ipykernel) +# language: python +# name: python3 +# --- + +# %% [markdown] +# # Datasets +# +# Datasets are `Iterable` (through their `__getitem__` and `__len__` attribute). +# Datasets are provided to `DataLoaders` which perform the aggreation to batches. + +# %% +import random +import numpy as np +import pandas as pd +import vaep.io.datasets as datasets +import vaep.utils as test_data + +# %% +N, M = 15, 7 +data = test_data.create_random_missing_data(N, M, prop_missing=.4) + +# %% [markdown] +# ## Datasets +# +# - `PeptideDatasetInMemory` +# - `PeptideDatasetInMemoryMasked` +# - `PeptideDatasetInMemoryNoMissings` + +# %% [markdown] +# ## `DatasetWithMaskAndNoTarget` + +# %% +dataset = datasets.DatasetWithMaskAndNoTarget(df=pd.DataFrame(data)) +for _mask, _array in dataset: + break +_array, _mask + +# %% [markdown] +# ### `PeptideDatasetInMemory` +# +# - with duplicated target in memory + +# %% +dataset = datasets.PeptideDatasetInMemory(data) +for _array, _mask, _target in dataset: + break +_array, _mask, _target + +# %% +id(_array), id(_mask), id(_target) + +# %% +_array is _target # should be true + +# %% +data = test_data.create_random_missing_data(N, M, prop_missing=0.3) +dataset = datasets.PeptideDatasetInMemoryMasked(df=pd.DataFrame(data), fill_na=25.0) + +for _array, _mask in dataset: + if any(_mask): + print(_array, _mask) + break + +# %% [markdown] +# ### `DatasetWithTarget` + +# %% +data = test_data.create_random_missing_data(N, M, prop_missing=0.3) +dataset = datasets.DatasetWithTarget(df=pd.DataFrame(data)) + +for _mask, _array, target in dataset: + if any(_mask): + print(_array, _mask, target, sep='\n') + break + +# %% [markdown] +# ### `DatasetWithTargetSpecifyTarget` + +# %% +data = test_data.create_random_missing_data(N, M, prop_missing=0.2) + +df = pd.DataFrame(data) + +val_y = df.stack().groupby(level=0).sample(frac=0.2) +# targets = val_y.unstack().sort_index() +targets = val_y.unstack() + +df[targets.notna()] = pd.NA +df + +# %% [markdown] +# The targets are complementary + +# %% +targets + +# %% +dataset = datasets.DatasetWithTargetSpecifyTarget(df=df, targets=targets) +for _mask, _array, target in dataset: + if any(_mask): + print(_mask, _array, target, sep='\n') + break + +# %% +row = random.randint(0,len(dataset)-1) +print(f"{row = }") +dataset[row] + +# %% [markdown] +# ### `PeptideDatasetInMemoryNoMissings` + +# %% +# data and pd.DataFrame.data share the same memory +try: + dataset = datasets.PeptideDatasetInMemoryNoMissings(data) + for _array in dataset: + print(_array) + break +except AssertionError as e: + print(e) + +# %% [markdown] +# ## DataLoaders +# +# FastAI DataLoaders accept pytorch datasets + +# %% +from fastai.collab import CollabDataLoaders +# , MSELossFlat, Learner +# from fastai.collab import EmbeddingDotBias + +from vaep.io.datasplits import long_format + + +data = pd.DataFrame(data) +data.index.name, data.columns.name = ('Sample ID', 'peptide') +df_long = long_format(pd.DataFrame(data)) +df_long.reset_index(inplace=True) +df_long.head() + +# %% +dls = CollabDataLoaders.from_df(df_long, valid_pct=0.15, + user_name='Sample ID', item_name='peptide', rating_name='intensity', + bs=4) +type(dls.dataset), dls.dataset._dl_type # no __mro__? + +# %% [markdown] +# Iterating over the dataset gives the column names + +# %% +for x in dls.dataset: + print(x) + +# %% [markdown] +# Training DataFrame is hidden under items + +# %% +dls.dataset.items + +# %% +for x in dls.train_ds: + print(x) + break + +# %% +dls.train_ds + +# %% [markdown] +# Iterating over the dataset returns columns, not single rows + +# %% +# dls.train_ds.__getitem__?? + +# %% +dls.train_ds.items['Sample ID'] + +# %% [markdown] +# But the `DataLoader` return the numeric representation in batches: + +# %% +for batch in dls.train_ds: + break +batch + +# %% +# dls.train.__iter__?? + +# %% +from torch.utils.data.dataloader import _SingleProcessDataLoaderIter +# _SingleProcessDataLoaderIter?? + +# %% [markdown] +# So.. It seems too complicated +# - the `_collate_fn` seems to aggrete the data from the DataFrame +# - should be possible to keep track of that + +# %% +next(iter(dls.dataset)) + + +# %% diff --git a/project/misc_sampling_in_pandas.ipynb b/project/misc_sampling_in_pandas.ipynb index 6bb163201..05500f95d 100644 --- a/project/misc_sampling_in_pandas.ipynb +++ b/project/misc_sampling_in_pandas.ipynb @@ -305,9 +305,9 @@ ], "metadata": { "kernelspec": { - "display_name": "vaep", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "vaep" + "name": "python3" }, "language_info": { "codemirror_mode": { diff --git a/project/misc_sampling_in_pandas.py b/project/misc_sampling_in_pandas.py new file mode 100644 index 000000000..0924f7453 --- /dev/null +++ b/project/misc_sampling_in_pandas.py @@ -0,0 +1,132 @@ +# --- +# jupyter: +# jupytext: +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.15.2 +# kernelspec: +# display_name: Python 3 (ipykernel) +# language: python +# name: python3 +# --- + +# %% [markdown] +# ## Sampling with weights in Pandas +# +# - sampling core utilities is based on numpy (see docstring) +# - [file](https://github.com/pandas-dev/pandas/blob/49d371364b734b47c85733aac74b03ac4400c629/pandas/core/sample.py) containing sampling functions + +# %% [markdown] +# ## Some random data + +# %% +from vaep.utils import create_random_df +X = create_random_df(100, 15, prop_na=0.1).stack().to_frame( + 'intensity').reset_index() + +freq = X.peptide.value_counts().sort_index() +freq.name = 'freq' + +X = X.set_index(keys=list(X.columns[0:2])) # to_list as an alternative +freq + +# %% +X + +# %% +print(f"Based on total number of rows, 95% is roughly: {int(len(X) * 0.95)}") +print("Based on each sample's 95% obs, it is roughly: {}".format( + X.groupby('Sample ID').apply(lambda df: int(len(df) * 0.95)).sum())) + +# %% [markdown] +# ## Samling using a column with the weights + +# %% +X = X.join(freq, on='peptide') +X + +# %% +t = X.groupby('Sample ID').get_group('sample_003') +t + +# %% +t.sample(frac=0.75, weights='freq') + +# %% [markdown] +# Sampling the entire DataFrame based on the freq will normalize on N of all rows. The normalization leaves relative frequency the same (if no floating point unprecision is reached) + +# %% +# number of rows not the same as when using groupby (see above) +X.sample(frac=0.95, weights='freq') + +# %% [markdown] +# ### Sampling fails with groupby, reindexing needed + +# %% [markdown] +# The above is not mapped one to one to the groupby sample method. One needs to apply it to every single df. + +# %% +# X.groupby('Sample ID').sample(frac=0.95, weights='freq') # does not work +X.groupby('Sample ID').apply( + lambda df: df.reset_index(0, drop=True).sample(frac=0.95, weights='freq') +).drop('freq', axis=1) + +# %% [markdown] +# And passing a Series need the original X to be indexed the same (multi-indices are not supported) + +# %% +# for i, t in X.groupby('Sample ID'): +# t = t.sample(frac=0.75, weights=freq) +# t + +# %% +X = X.reset_index('Sample ID') +X + +# %% +X.groupby(by='Sample ID').sample(frac=0.95, weights=freq) + +# %% +X.groupby(by='Sample ID').get_group('sample_002') + +# %% [markdown] +# ## Sanity check: Downsampling the first feature + +# %% +freq.loc['feat_00'] = 1 # none should be selected + +# %% +freq = freq / freq.sum() +freq + +# %% +X.groupby(by='Sample ID').sample( + frac=0.5, weights=freq).sort_index().reset_index().peptide.value_counts() + +# %% [markdown] +# ## Using a series +# +# - in the above approach, sampling weights might be readjusted based on the values present in `sample` as `NAN`s lead to the weights not summing up. Alteratively one could loop through the wide format rows and sample values from these. + +# %% +freq + +# %% +X = X.drop('freq', axis=1).set_index( + 'Sample ID', append=True).squeeze().unstack(0) +X + +# %% +X.iloc[0].sample(frac=0.8, weights=freq).sort_index() + +# %% [markdown] +# Sampling using the wide format would garuantee that the weights are not adjusted based on missing values, but that instead missing values are sample into on or the other set. Ultimately `NaN`s are dropped also in this approach. + +# %% +import pandas as pd +data = {} +for row_key in X.index: + data[row_key] = X.loc[row_key].sample(frac=0.8, weights=freq) +pd.DataFrame(data).stack() diff --git a/project/workflow/README.md b/project/workflow/README.md index 477c6c61b..f0a9f6d2c 100644 --- a/project/workflow/README.md +++ b/project/workflow/README.md @@ -92,4 +92,8 @@ Executes both workflows for model training and comparison ten times: - `nolock` : ensure that parent workflow does not block child workflow ```bash snakemake -s workflow\Snakefile_ald_comparison_repeated.smk -p -c1 --nolock --drop-metadata -F -n -``` \ No newline at end of file +``` + +## Test `misc_` notebook + +`TestNotebooks.smk` test the `misc_*` notebooks in the project folder. \ No newline at end of file From 500220dcfb935609ee6a2181789965c11c39646a Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Wed, 1 Nov 2023 21:11:49 +0100 Subject: [PATCH 39/70] :memo: add version for base workflow configuration (Snakefile vs Snakefile_v2) --- project/config/across_datasets/config.yaml | 1 + project/config/appl_ald_data/plasma/proteinGroups/config.yaml | 1 + project/config/knn_comparison/ald_pgs_all/config.yaml | 1 + project/config/knn_comparison/hela_pgs_large/config.yaml | 1 + project/config/single_dev_dataset/evidence_N50/config.yaml | 1 + project/config/single_dev_dataset/example/config.yaml | 1 + project/config/single_dev_dataset/peptides_N50/config.yaml | 1 + project/config/single_dev_dataset/proteinGroups_N50/config.yaml | 1 + 8 files changed, 8 insertions(+) diff --git a/project/config/across_datasets/config.yaml b/project/config/across_datasets/config.yaml index f7a75f630..1e278aa07 100644 --- a/project/config/across_datasets/config.yaml +++ b/project/config/across_datasets/config.yaml @@ -1,3 +1,4 @@ +# # config for Snakefile_best_across_datasets epochs_max: - 100 batch_size: 64 diff --git a/project/config/appl_ald_data/plasma/proteinGroups/config.yaml b/project/config/appl_ald_data/plasma/proteinGroups/config.yaml index 24a8a3880..af955b8ae 100644 --- a/project/config/appl_ald_data/plasma/proteinGroups/config.yaml +++ b/project/config/appl_ald_data/plasma/proteinGroups/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v1 config_split: config/appl_ald_data/plasma/proteinGroups/split.yaml config_train: config/appl_ald_data/plasma/proteinGroups/train_{model}.yaml folder_experiment: runs/appl_ald_data/plasma/proteinGroups diff --git a/project/config/knn_comparison/ald_pgs_all/config.yaml b/project/config/knn_comparison/ald_pgs_all/config.yaml index 149413972..96c85270a 100644 --- a/project/config/knn_comparison/ald_pgs_all/config.yaml +++ b/project/config/knn_comparison/ald_pgs_all/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v2 config_train: runs/knn_comparison/ald_pgs_all/configs_train/train_{model}.yaml folder_experiment: runs/knn_comparison/ald_pgs_all fn_rawfile_metadata: data/ALD_study/processed/raw_meta.csv diff --git a/project/config/knn_comparison/hela_pgs_large/config.yaml b/project/config/knn_comparison/hela_pgs_large/config.yaml index 160b92411..e618a31a3 100644 --- a/project/config/knn_comparison/hela_pgs_large/config.yaml +++ b/project/config/knn_comparison/hela_pgs_large/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v2 config_split: config/knn_comparison/hela_pgs_large/split.yaml config_train: runs/knn_comparison/hela_pgs_large/configs_train/train_{model}.yaml folder_experiment: runs/knn_comparison/hela_pgs_large diff --git a/project/config/single_dev_dataset/evidence_N50/config.yaml b/project/config/single_dev_dataset/evidence_N50/config.yaml index 2884b973d..fea06b5df 100644 --- a/project/config/single_dev_dataset/evidence_N50/config.yaml +++ b/project/config/single_dev_dataset/evidence_N50/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v1 config_split: config/single_dev_dataset/evidence_N50/split.yaml config_train: config/single_dev_dataset/evidence_N50/train_{model}.yaml folder_experiment: runs/dev_dataset_small/evidence_N50 diff --git a/project/config/single_dev_dataset/example/config.yaml b/project/config/single_dev_dataset/example/config.yaml index 4f32f8b2b..432ac518d 100644 --- a/project/config/single_dev_dataset/example/config.yaml +++ b/project/config/single_dev_dataset/example/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v1 config_split: config/single_dev_dataset/example/split.yaml config_train: config/single_dev_dataset/example/train_{model}.yaml folder_experiment: runs/example diff --git a/project/config/single_dev_dataset/peptides_N50/config.yaml b/project/config/single_dev_dataset/peptides_N50/config.yaml index 612099b93..91888760c 100644 --- a/project/config/single_dev_dataset/peptides_N50/config.yaml +++ b/project/config/single_dev_dataset/peptides_N50/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v1 config_split: config/single_dev_dataset/peptides_N50/split.yaml config_train: config/single_dev_dataset/peptides_N50/train_{model}.yaml folder_experiment: runs/dev_dataset_small/peptides_N50 diff --git a/project/config/single_dev_dataset/proteinGroups_N50/config.yaml b/project/config/single_dev_dataset/proteinGroups_N50/config.yaml index 3db585591..6c8335674 100644 --- a/project/config/single_dev_dataset/proteinGroups_N50/config.yaml +++ b/project/config/single_dev_dataset/proteinGroups_N50/config.yaml @@ -1,3 +1,4 @@ +# config for Snakefile_v1 config_split: config/single_dev_dataset/proteinGroups_N50/split.yaml config_train: config/single_dev_dataset/proteinGroups_N50/train_{model}.yaml folder_experiment: runs/dev_dataset_small/proteinGroups_N50 From f46777bbcebba72c9a6048b099a3f9d0cc9781cf Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Fri, 3 Nov 2023 16:33:12 +0100 Subject: [PATCH 40/70] :error: update expected rule output - msImpute and trKNN failed --- project/workflow/Snakefile_small_N.smk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/workflow/Snakefile_small_N.smk b/project/workflow/Snakefile_small_N.smk index 398dfb349..807f7d211 100644 --- a/project/workflow/Snakefile_small_N.smk +++ b/project/workflow/Snakefile_small_N.smk @@ -90,7 +90,7 @@ use rule comparison from single_experiment as adapted_comparison with: ), output: xlsx="{folder_experiment}/01_2_performance_summary.xlsx", - pdf="{folder_experiment}/figures/errors_binned_by_int_test.pdf", + pdf="{folder_experiment}/figures/2_1_test_errors_binned_by_int.pdf", nb="{folder_experiment}" f"/{nb}", From c849cb549b10358ea821b7b42278fa9f60ae15c0 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Wed, 8 Nov 2023 17:23:00 +0100 Subject: [PATCH 41/70] :memo: document distributed cluster execution --- project/bin/README.md | 18 ++++++++++++++++++ project/bin/run_snakemake.sh | 4 ++-- project/workflow/bin/README.md | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 project/bin/README.md create mode 100644 project/workflow/bin/README.md diff --git a/project/bin/README.md b/project/bin/README.md new file mode 100644 index 000000000..3e84a2791 --- /dev/null +++ b/project/bin/README.md @@ -0,0 +1,18 @@ +# Computerome2 (CR2) scripts + +Cluster exectuion script for CR2 using a torque-pbs queue. + + +## Distributed + +```bash +qsub run_snakemake_cluster.sh -N snakemake_exp -v configfile=config/single_dev_dataset/example/config.yaml,prefix=exp +``` + +## Single node + +```bash +qsub run_snakemake.sh -N grid_exp +``` + + diff --git a/project/bin/run_snakemake.sh b/project/bin/run_snakemake.sh index e01a13255..9b7b2d032 100644 --- a/project/bin/run_snakemake.sh +++ b/project/bin/run_snakemake.sh @@ -5,8 +5,8 @@ ### Job name (comment out the next line to get the name of the script used as the job name) #PBS -N sn_grid ### Output files (comment out the next 2 lines to get the job name used instead) -#PBS -e qsub_logs${PBS_JOBNAME}.${PBS_JOBID}.e -#PBS -o qsub_logs${PBS_JOBNAME}.${PBS_JOBID}.o +#PBS -e qsub_logs/${PBS_JOBNAME}.${PBS_JOBID}.e +#PBS -o qsub_logs/${PBS_JOBNAME}.${PBS_JOBID}.o ### Email notification: a=aborts, b=begins, e=ends, n=no notifications #PBS -m ae -M henry.webel@cpr.ku.dk ### Number of nodes diff --git a/project/workflow/bin/README.md b/project/workflow/bin/README.md new file mode 100644 index 000000000..a45c2b8a8 --- /dev/null +++ b/project/workflow/bin/README.md @@ -0,0 +1,14 @@ +# Scripts for pbs-torque cluster execution + +We ran the software partly on a pbs-torque cluster + +`qsub-status_v2.py` is used by snakemake to query the status of a submitted job in case the job, +in case the job is not ran locally within the main process running snakemake. + +`create_qsub_commands.py` is a script which create some job submission commands. + +`jobscript.sh` is a script which sets up conda before the subcommand create from within +a snakemake job is run. + + +> None of this is needed in case snakemake is non-distributed on a single node. \ No newline at end of file From 26213e59f2fa1063c33c4242fa25f8a95f158b93 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 9 Nov 2023 13:07:55 +0100 Subject: [PATCH 42/70] :art: format R code --- project/01_1_train_NAGuideR_methods.R | 472 +++++++++++---------- project/01_1_train_NAGuideR_methods.ipynb | 474 ++++++++++++---------- 2 files changed, 525 insertions(+), 421 deletions(-) diff --git a/project/01_1_train_NAGuideR_methods.R b/project/01_1_train_NAGuideR_methods.R index 2b21d7e32..d39d5d674 100644 --- a/project/01_1_train_NAGuideR_methods.R +++ b/project/01_1_train_NAGuideR_methods.R @@ -20,30 +20,32 @@ # - BiocManager could be moved to methods who are installed from BioConductor # + vscode={"languageId": "r"} -packages_base_R <- c("BiocManager", "reshape2", "data.table", "readr", "tibble") +packages_base_R <- + c("BiocManager", "reshape2", "data.table", "readr", "tibble") -install_rpackage <- function(pkg){ - # If not installed, install the package - if (!require(pkg, character.only = TRUE)) { - install.packages(pkg) - library(pkg, character.only = TRUE) - } - +install_rpackage <- function(pkg) { + # If not installed, install the package + if (!require(pkg, character.only = TRUE)) { + install.packages(pkg) + library(pkg, character.only = TRUE) + } + } # used in the large imputation function for two packages -install_bioconductor <- function(pkg){ - # If not installed, install the package - if (!require(pkg, character.only = TRUE)) { - BiocManager::install(pkg) - library(pkg, character.only = TRUE) - } - +install_bioconductor <- function(pkg) { + # If not installed, install the package + if (!require(pkg, character.only = TRUE)) { + BiocManager::install(pkg) + library(pkg, character.only = TRUE) + } + } + for (package in packages_base_R) { # Check if the package is already installed - install_rpackage(pkg=package) + install_rpackage(pkg = package) } # - @@ -57,177 +59,218 @@ for (package in packages_base_R) { # - code is only slightly adapted from repo to run here, mainly to install packages on the fly # + vscode={"languageId": "r"} -nafunctions <- function(x,method="zero"){ - df<-df1<-as.data.frame(x) - method<-tolower(method) - if(method=="zero"){ - df[is.na(df)]<-0 - } - else if(method=="minimum"){ - df[is.na(df)]<-min(df1,na.rm = TRUE) - } - else if(method=="colmedian"){ - install_rpackage('e1071') - df<-impute(df1,what ="median") - } - else if(method=="rowmedian"){ - install_rpackage('e1071') - dfx<-impute(t(df1),what ="median") - df<-t(dfx) - } - else if(method=="knn_impute"){ - install_bioconductor('impute') - data_zero1<-impute.knn(as.matrix(df1),k = 10, rowmax = 1, colmax = 1)#rowmax = 0.9, colmax = 0.9 - df<-data_zero1$data - } - else if(method=="seqknn"){ - if(!require(SeqKnn)){ - install.packages("src/R_NAGuideR/SeqKnn_1.0.1.tar.gz", repos = NULL,type="source") - library(SeqKnn) - } - df <- SeqKNN(df1,k = 10) - } - else if(method=="bpca"){ - install_bioconductor('pcaMethods') - data_zero1<-pcaMethods::pca(as.matrix(df1), nPcs = ncol(df1)-1, method = "bpca", maxSteps =100) - df<-completeObs(data_zero1) - } - else if(method=="svdmethod"){ - install_bioconductor('pcaMethods') - data_zero1<-pcaMethods::pca(as.matrix(df1), nPcs = ncol(df1)-1, method = "svdImpute") - df<-completeObs(data_zero1) - } - else if(method=="lls"){ - install_bioconductor('pcaMethods') - data_zero1<-llsImpute(t(df1), k = 10) - df<-t(completeObs(data_zero1)) - } - else if(method=="mle"){ - install_rpackage('norm') - xxm<-as.matrix(df1) - ss <- norm::prelim.norm(xxm) - thx <- norm::em.norm(ss) - norm::rngseed(123) - df <- norm::imp.norm(ss, thx, xxm) - } - else if(method=="qrilc"){ - install_bioconductor("impute") - install_bioconductor("pcaMethods") - install_rpackage('imputeLCMD') - xxm<-t(df1) - data_zero1 <- imputeLCMD::impute.QRILC(xxm, tune.sigma = 1)[[1]] - df<-t(data_zero1) - } - else if(method=="mindet"){ - install_bioconductor("impute") - install_bioconductor("pcaMethods") - install_rpackage('imputeLCMD') - xxm<-as.matrix(df1) - df <- imputeLCMD::impute.MinDet(xxm, q = 0.01) - } - else if(method=="minprob"){ - install_bioconductor("impute") - install_bioconductor("pcaMethods") - install_rpackage('imputeLCMD') - xxm<-as.matrix(df1) - df <- imputeLCMD::impute.MinProb(xxm, q = 0.01, tune.sigma = 1) - } - else if(method=="irm"){ - install_rpackage('VIM') - df <- irmi(df1, trace = TRUE,imp_var=FALSE) - rownames(df)<-rownames(df1) - } - else if(method=="impseq"){ - install_rpackage('rrcovNA') - df <- impSeq(df1) - } - else if(method=="impseqrob"){ - install_rpackage('rrcovNA') - data_zero1 <- impSeqRob(df1, alpha=0.9) - df<-data_zero1$x - } - else if(method=="mice-norm"){ - install_rpackage('mice') - minum<-5 - datareadmi<-mice(df1,m=minum,seed = 1234, method ="norm") - newdatareadmi<-0 - for (i in 1:minum) { - newdatareadmi<-complete(datareadmi,action = i)+newdatareadmi - } - df<-newdatareadmi/minum - rownames(df)<-rownames(df1) - } - else if(method=="mice-cart"){ - install_rpackage('mice') - minum<-5 - datareadmi<-mice(df1,m=minum,seed = 1234, method ="cart") - newdatareadmi<-0 - for (i in 1:minum) { - newdatareadmi<-complete(datareadmi,action = i)+newdatareadmi - } - df<-newdatareadmi/minum - rownames(df)<-rownames(df1) - } - else if(method=="trknn"){ - source('src/R_NAGuideR/Imput_funcs.r') - # sim_trKNN_wrapper <- function(data) { - # result <- data %>% as.matrix %>% t %>% imputeKNN(., k=10, distance='truncation', perc=0) %>% t - # return(result) - # } - # df1x <- sim_trKNN_wrapper(t(df1)) - # df<-as.data.frame(t(df1x)) - df <- imputeKNN(as.matrix(df), k=10, distance='truncation', perc=0) - df <- as.data.frame(df) +nafunctions <- function(x, method = "zero") { + df <- df1 <- as.data.frame(x) + method <- tolower(method) + if (method == "zero") { + df[is.na(df)] <- 0 + } + else if (method == "minimum") { + df[is.na(df)] <- min(df1, na.rm = TRUE) + } + else if (method == "colmedian") { + install_rpackage('e1071') + df <- impute(df1, what = "median") + } + else if (method == "rowmedian") { + install_rpackage('e1071') + dfx <- impute(t(df1), what = "median") + df <- t(dfx) + } + else if (method == "knn_impute") { + install_bioconductor('impute') + data_zero1 <- + impute.knn(as.matrix(df1), + k = 10, + rowmax = 1, + colmax = 1)#rowmax = 0.9, colmax = 0.9 + df <- data_zero1$data + } + else if (method == "seqknn") { + if (!require(SeqKnn)) { + install.packages("src/R_NAGuideR/SeqKnn_1.0.1.tar.gz", + repos = NULL, + type = "source") + library(SeqKnn) } - else if(method=="rf"){ - install_rpackage("missForest") - data_zero1 <- missForest(t(df1), maxiter =10, - ntree = 20 # input$rfntrees - ,mtry=floor(nrow(df1)^(1/3)),verbose = TRUE) - df<-t(data_zero1$ximp) + df <- SeqKNN(df1, k = 10) + } + else if (method == "bpca") { + install_bioconductor('pcaMethods') + data_zero1 <- + pcaMethods::pca( + as.matrix(df1), + nPcs = ncol(df1) - 1, + method = "bpca", + maxSteps = 100 + ) + df <- completeObs(data_zero1) + } + else if (method == "svdmethod") { + install_bioconductor('pcaMethods') + data_zero1 <- + pcaMethods::pca(as.matrix(df1), + nPcs = ncol(df1) - 1, + method = "svdImpute") + df <- completeObs(data_zero1) + } + else if (method == "lls") { + install_bioconductor('pcaMethods') + data_zero1 <- llsImpute(t(df1), k = 10) + df <- t(completeObs(data_zero1)) + } + else if (method == "mle") { + install_rpackage('norm') + xxm <- as.matrix(df1) + ss <- norm::prelim.norm(xxm) + thx <- norm::em.norm(ss) + norm::rngseed(123) + df <- norm::imp.norm(ss, thx, xxm) + } + else if (method == "qrilc") { + install_bioconductor("impute") + install_bioconductor("pcaMethods") + install_rpackage('imputeLCMD') + xxm <- t(df1) + data_zero1 <- + imputeLCMD::impute.QRILC(xxm, tune.sigma = 1)[[1]] + df <- t(data_zero1) + } + else if (method == "mindet") { + install_bioconductor("impute") + install_bioconductor("pcaMethods") + install_rpackage('imputeLCMD') + xxm <- as.matrix(df1) + df <- imputeLCMD::impute.MinDet(xxm, q = 0.01) + } + else if (method == "minprob") { + install_bioconductor("impute") + install_bioconductor("pcaMethods") + install_rpackage('imputeLCMD') + xxm <- as.matrix(df1) + df <- + imputeLCMD::impute.MinProb(xxm, q = 0.01, tune.sigma = 1) + } + else if (method == "irm") { + install_rpackage('VIM') + df <- irmi(df1, trace = TRUE, imp_var = FALSE) + rownames(df) <- rownames(df1) + } + else if (method == "impseq") { + install_rpackage('rrcovNA') + df <- impSeq(df1) + } + else if (method == "impseqrob") { + install_rpackage('rrcovNA') + data_zero1 <- impSeqRob(df1, alpha = 0.9) + df <- data_zero1$x + } + else if (method == "mice-norm") { + install_rpackage('mice') + minum <- 5 + datareadmi <- mice(df1, + m = minum, + seed = 1234, + method = "norm") + newdatareadmi <- 0 + for (i in 1:minum) { + newdatareadmi <- complete(datareadmi, action = i) + newdatareadmi } - else if(method=="pi"){ - width <- 0.3 # input$piwidth - downshift <- 1.8 # input$pidownshift - for(i in 1:ncol(df1)){ - temp <- df1[[i]] - if(sum(is.na(temp))>0){ - temp.sd <- width * sd(temp[!is.na(temp)], na.rm = TRUE) - temp.mean <- mean(temp[!is.na(temp)], na.rm = TRUE) - downshift * sd(temp[!is.na(temp)], na.rm = TRUE) - n.missing <- sum(is.na(temp)) - temp[is.na(temp)] <- rnorm(n.missing, mean = temp.mean, sd = temp.sd) - df[[i]]<-temp - } - } - df + df <- newdatareadmi / minum + rownames(df) <- rownames(df1) + } + else if (method == "mice-cart") { + install_rpackage('mice') + minum <- 5 + datareadmi <- mice(df1, + m = minum, + seed = 1234, + method = "cart") + newdatareadmi <- 0 + for (i in 1:minum) { + newdatareadmi <- complete(datareadmi, action = i) + newdatareadmi } - # else if(method=="grr"){ - # library(DreamAI) - # df<-impute.RegImpute(data=as.matrix(df1), fillmethod = "row_mean", maxiter_RegImpute = 10,conv_nrmse = 1e-03) + df <- newdatareadmi / minum + rownames(df) <- rownames(df1) + } + else if (method == "trknn") { + source('src/R_NAGuideR/Imput_funcs.r') + # sim_trKNN_wrapper <- function(data) { + # result <- data %>% as.matrix %>% t %>% imputeKNN(., k=10, distance='truncation', perc=0) %>% t + # return(result) # } - else if(method=="gms"){ - # install.packages('GMSimpute') - if(!require(GMSimpute)){ - install.packages("src/R_NAGuideR/GMSimpute_0.0.1.1.tar.gz", repos = NULL, type="source"); - library(GMSimpute) + # df1x <- sim_trKNN_wrapper(t(df1)) + # df<-as.data.frame(t(df1x)) + df <- + imputeKNN(as.matrix(df), + k = 10, + distance = 'truncation', + perc = 0) + df <- as.data.frame(df) + } + else if (method == "rf") { + install_rpackage("missForest") + data_zero1 <- missForest( + t(df1), + maxiter = 10, + ntree = 20 # input$rfntrees + , + mtry = floor(nrow(df1) ^ (1 / 3)), + verbose = TRUE + ) + df <- t(data_zero1$ximp) + } + else if (method == "pi") { + width <- 0.3 # input$piwidth + downshift <- 1.8 # input$pidownshift + for (i in 1:ncol(df1)) { + temp <- df1[[i]] + if (sum(is.na(temp)) > 0) { + temp.sd <- width * sd(temp[!is.na(temp)], na.rm = TRUE) + temp.mean <- + mean(temp[!is.na(temp)], na.rm = TRUE) - downshift * sd(temp[!is.na(temp)], na.rm = TRUE) + n.missing <- sum(is.na(temp)) + temp[is.na(temp)] <- + rnorm(n.missing, mean = temp.mean, sd = temp.sd) + df[[i]] <- temp } - - df<-GMS.Lasso(df1,nfolds=3,log.scale=FALSE,TS.Lasso=TRUE) - } - else if(method=="msimpute"){ - install_bioconductor("msImpute") - df <- msImpute(as.matrix(df), method='v2') - df <- as.data.frame(df) } - else{ - stop(paste("Unspported methods so far: ", method)) + df + } + # else if(method=="grr"){ + # library(DreamAI) + # df<-impute.RegImpute(data=as.matrix(df1), fillmethod = "row_mean", maxiter_RegImpute = 10,conv_nrmse = 1e-03) + # } + else if (method == "gms") { + # install.packages('GMSimpute') + if (!require(GMSimpute)) { + install.packages( + "src/R_NAGuideR/GMSimpute_0.0.1.1.tar.gz", + repos = NULL, + type = "source" + ) + + library(GMSimpute) } + + df <- GMS.Lasso(df1, + nfolds = 3, + log.scale = FALSE, + TS.Lasso = TRUE) + } + else if (method == "msimpute") { + install_bioconductor("msImpute") + df <- msImpute(as.matrix(df), method = 'v2') df <- as.data.frame(df) - df } + else{ + stop(paste("Unspported methods so far: ", method)) + } + df <- as.data.frame(df) + df +} # - - # ## Parameters # # Choose one of the available methods. Some methods might fail for your dataset for unknown reasons (and the error won't always be easy to under) @@ -265,7 +308,13 @@ method = 'KNN_IMPUTE' # ## Dump predictions # + vscode={"languageId": "r"} -df <- utils::read.csv(train_split, row.names=1, header=TRUE, stringsAsFactors = FALSE) +df <- + utils::read.csv( + train_split, + row.names = 1, + header = TRUE, + stringsAsFactors = FALSE + ) df # - @@ -273,9 +322,12 @@ df # - tibbles don't support rownames, and the imputation methods rely on normal `data.frame`s. Save the header row for later use. # + vscode={"languageId": "r"} -original_header <- colnames( - readr::read_csv(train_split, n_max=1, col_names=TRUE, skip=0) -) +original_header <- colnames(readr::read_csv( + train_split, + n_max = 1, + col_names = TRUE, + skip = 0 +)) feat_name <- original_header[1] original_header[1:5] # - @@ -284,30 +336,30 @@ original_header[1:5] # + vscode={"languageId": "r"} # to_test <- c( - # 'ZERO', - # 'MINIMUM', - # 'COLMEDIAN', - # 'ROWMEDIAN', - # 'KNN_IMPUTE', - # 'SEQKNN', - # 'BPCA', - # 'SVDMETHOD', - # 'LLS', - # 'MLE', - # 'LLS', - # 'QRILC', - # 'MINDET', - # 'MINPROB', - # 'IRM', - # 'IMPSEQ', - # 'IMPSEQROB', - # 'MICE-NORM', - # 'MICE-CART', - # 'RF', - # 'PI', - # 'GMS', # fails to install on Windows - # 'trknn', - # 'msimpute' +# 'ZERO', +# 'MINIMUM', +# 'COLMEDIAN', +# 'ROWMEDIAN', +# 'KNN_IMPUTE', +# 'SEQKNN', +# 'BPCA', +# 'SVDMETHOD', +# 'LLS', +# 'MLE', +# 'LLS', +# 'QRILC', +# 'MINDET', +# 'MINPROB', +# 'IRM', +# 'IMPSEQ', +# 'IMPSEQROB', +# 'MICE-NORM', +# 'MICE-CART', +# 'RF', +# 'PI', +# 'GMS', # fails to install on Windows +# 'trknn', +# 'msimpute' # ) # for (method in to_test) { @@ -320,13 +372,11 @@ original_header[1:5] # + vscode={"languageId": "r"} pred <- nafunctions(df, method) -pred <- tibble::as_tibble( - cbind(rownames(pred), pred) -) +pred <- tibble::as_tibble(cbind(rownames(pred), pred)) names(pred) <- original_header pred # + vscode={"languageId": "r"} -pred <- reshape2::melt(pred, id.vars=feat_name) +pred <- reshape2::melt(pred, id.vars = feat_name) names(pred) <- c(feat_name, 'Sample ID', method) pred <- pred[reshape2::melt(is.na(df))['value'] == TRUE, ] pred @@ -335,8 +385,10 @@ pred dim(pred) # + vscode={"languageId": "r"} -fname = file.path(folder_experiment, 'preds', paste0('pred_all_', toupper(method), '.csv')) +fname = file.path(folder_experiment, + 'preds', + paste0('pred_all_', toupper(method), '.csv')) fname # + vscode={"languageId": "r"} -write_csv(pred, path=fname) +write_csv(pred, path = fname) diff --git a/project/01_1_train_NAGuideR_methods.ipynb b/project/01_1_train_NAGuideR_methods.ipynb index 41ed54001..fb6a72b19 100644 --- a/project/01_1_train_NAGuideR_methods.ipynb +++ b/project/01_1_train_NAGuideR_methods.ipynb @@ -23,30 +23,32 @@ }, "outputs": [], "source": [ - "packages_base_R <- c(\"BiocManager\", \"reshape2\", \"data.table\", \"readr\", \"tibble\")\n", + "packages_base_R <-\n", + " c(\"BiocManager\", \"reshape2\", \"data.table\", \"readr\", \"tibble\")\n", "\n", - "install_rpackage <- function(pkg){\n", - " # If not installed, install the package\n", - " if (!require(pkg, character.only = TRUE)) {\n", - " install.packages(pkg)\n", - " library(pkg, character.only = TRUE)\n", - " }\n", - " \n", + "install_rpackage <- function(pkg) {\n", + " # If not installed, install the package\n", + " if (!require(pkg, character.only = TRUE)) {\n", + " install.packages(pkg)\n", + " library(pkg, character.only = TRUE)\n", + " }\n", + " \n", "}\n", "\n", "# used in the large imputation function for two packages\n", - "install_bioconductor <- function(pkg){\n", - " # If not installed, install the package\n", - " if (!require(pkg, character.only = TRUE)) {\n", - " BiocManager::install(pkg)\n", - " library(pkg, character.only = TRUE)\n", - " }\n", - " \n", + "install_bioconductor <- function(pkg) {\n", + " # If not installed, install the package\n", + " if (!require(pkg, character.only = TRUE)) {\n", + " BiocManager::install(pkg)\n", + " library(pkg, character.only = TRUE)\n", + " }\n", + " \n", "}\n", "\n", + "\n", "for (package in packages_base_R) {\n", " # Check if the package is already installed\n", - " install_rpackage(pkg=package)\n", + " install_rpackage(pkg = package)\n", "}\n" ] }, @@ -75,181 +77,222 @@ "execution_count": null, "id": "f9c48bf7-d31c-4073-895b-e9cf920ff1d3", "metadata": { - "lines_to_next_cell": 2, "vscode": { "languageId": "r" } }, "outputs": [], "source": [ - "nafunctions <- function(x,method=\"zero\"){\n", - " df<-df1<-as.data.frame(x)\n", - " method<-tolower(method)\n", - " if(method==\"zero\"){\n", - " df[is.na(df)]<-0\n", - " }\n", - " else if(method==\"minimum\"){\n", - " df[is.na(df)]<-min(df1,na.rm = TRUE)\n", - " }\n", - " else if(method==\"colmedian\"){\n", - " install_rpackage('e1071')\n", - " df<-impute(df1,what =\"median\")\n", - " }\n", - " else if(method==\"rowmedian\"){\n", - " install_rpackage('e1071')\n", - " dfx<-impute(t(df1),what =\"median\")\n", - " df<-t(dfx)\n", - " }\n", - " else if(method==\"knn_impute\"){\n", - " install_bioconductor('impute')\n", - " data_zero1<-impute.knn(as.matrix(df1),k = 10, rowmax = 1, colmax = 1)#rowmax = 0.9, colmax = 0.9\n", - " df<-data_zero1$data\n", - " }\n", - " else if(method==\"seqknn\"){\n", - " if(!require(SeqKnn)){\n", - " install.packages(\"src/R_NAGuideR/SeqKnn_1.0.1.tar.gz\", repos = NULL,type=\"source\")\n", - " library(SeqKnn)\n", - " }\n", - " df <- SeqKNN(df1,k = 10)\n", - " }\n", - " else if(method==\"bpca\"){\n", - " install_bioconductor('pcaMethods')\n", - " data_zero1<-pcaMethods::pca(as.matrix(df1), nPcs = ncol(df1)-1, method = \"bpca\", maxSteps =100)\n", - " df<-completeObs(data_zero1)\n", - " }\n", - " else if(method==\"svdmethod\"){\n", - " install_bioconductor('pcaMethods')\n", - " data_zero1<-pcaMethods::pca(as.matrix(df1), nPcs = ncol(df1)-1, method = \"svdImpute\")\n", - " df<-completeObs(data_zero1)\n", - " }\n", - " else if(method==\"lls\"){\n", - " install_bioconductor('pcaMethods')\n", - " data_zero1<-llsImpute(t(df1), k = 10)\n", - " df<-t(completeObs(data_zero1))\n", - " }\n", - " else if(method==\"mle\"){\n", - " install_rpackage('norm')\n", - " xxm<-as.matrix(df1)\n", - " ss <- norm::prelim.norm(xxm)\n", - " thx <- norm::em.norm(ss)\n", - " norm::rngseed(123)\n", - " df <- norm::imp.norm(ss, thx, xxm)\n", - " }\n", - " else if(method==\"qrilc\"){\n", - " install_bioconductor(\"impute\")\n", - " install_bioconductor(\"pcaMethods\")\n", - " install_rpackage('imputeLCMD')\n", - " xxm<-t(df1)\n", - " data_zero1 <- imputeLCMD::impute.QRILC(xxm, tune.sigma = 1)[[1]]\n", - " df<-t(data_zero1)\n", - " }\n", - " else if(method==\"mindet\"){\n", - " install_bioconductor(\"impute\")\n", - " install_bioconductor(\"pcaMethods\")\n", - " install_rpackage('imputeLCMD')\n", - " xxm<-as.matrix(df1)\n", - " df <- imputeLCMD::impute.MinDet(xxm, q = 0.01)\n", + "nafunctions <- function(x, method = \"zero\") {\n", + " df <- df1 <- as.data.frame(x)\n", + " method <- tolower(method)\n", + " if (method == \"zero\") {\n", + " df[is.na(df)] <- 0\n", + " }\n", + " else if (method == \"minimum\") {\n", + " df[is.na(df)] <- min(df1, na.rm = TRUE)\n", + " }\n", + " else if (method == \"colmedian\") {\n", + " install_rpackage('e1071')\n", + " df <- impute(df1, what = \"median\")\n", + " }\n", + " else if (method == \"rowmedian\") {\n", + " install_rpackage('e1071')\n", + " dfx <- impute(t(df1), what = \"median\")\n", + " df <- t(dfx)\n", + " }\n", + " else if (method == \"knn_impute\") {\n", + " install_bioconductor('impute')\n", + " data_zero1 <-\n", + " impute.knn(as.matrix(df1),\n", + " k = 10,\n", + " rowmax = 1,\n", + " colmax = 1)#rowmax = 0.9, colmax = 0.9\n", + " df <- data_zero1$data\n", + " }\n", + " else if (method == \"seqknn\") {\n", + " if (!require(SeqKnn)) {\n", + " install.packages(\"src/R_NAGuideR/SeqKnn_1.0.1.tar.gz\",\n", + " repos = NULL,\n", + " type = \"source\")\n", + " library(SeqKnn)\n", " }\n", - " else if(method==\"minprob\"){\n", - " install_bioconductor(\"impute\")\n", - " install_bioconductor(\"pcaMethods\")\n", - " install_rpackage('imputeLCMD')\n", - " xxm<-as.matrix(df1)\n", - " df <- imputeLCMD::impute.MinProb(xxm, q = 0.01, tune.sigma = 1)\n", + " df <- SeqKNN(df1, k = 10)\n", + " }\n", + " else if (method == \"bpca\") {\n", + " install_bioconductor('pcaMethods')\n", + " data_zero1 <-\n", + " pcaMethods::pca(\n", + " as.matrix(df1),\n", + " nPcs = ncol(df1) - 1,\n", + " method = \"bpca\",\n", + " maxSteps = 100\n", + " )\n", + " df <- completeObs(data_zero1)\n", + " }\n", + " else if (method == \"svdmethod\") {\n", + " install_bioconductor('pcaMethods')\n", + " data_zero1 <-\n", + " pcaMethods::pca(as.matrix(df1),\n", + " nPcs = ncol(df1) - 1,\n", + " method = \"svdImpute\")\n", + " df <- completeObs(data_zero1)\n", + " }\n", + " else if (method == \"lls\") {\n", + " install_bioconductor('pcaMethods')\n", + " data_zero1 <- llsImpute(t(df1), k = 10)\n", + " df <- t(completeObs(data_zero1))\n", + " }\n", + " else if (method == \"mle\") {\n", + " install_rpackage('norm')\n", + " xxm <- as.matrix(df1)\n", + " ss <- norm::prelim.norm(xxm)\n", + " thx <- norm::em.norm(ss)\n", + " norm::rngseed(123)\n", + " df <- norm::imp.norm(ss, thx, xxm)\n", + " }\n", + " else if (method == \"qrilc\") {\n", + " install_bioconductor(\"impute\")\n", + " install_bioconductor(\"pcaMethods\")\n", + " install_rpackage('imputeLCMD')\n", + " xxm <- t(df1)\n", + " data_zero1 <-\n", + " imputeLCMD::impute.QRILC(xxm, tune.sigma = 1)[[1]]\n", + " df <- t(data_zero1)\n", + " }\n", + " else if (method == \"mindet\") {\n", + " install_bioconductor(\"impute\")\n", + " install_bioconductor(\"pcaMethods\")\n", + " install_rpackage('imputeLCMD')\n", + " xxm <- as.matrix(df1)\n", + " df <- imputeLCMD::impute.MinDet(xxm, q = 0.01)\n", + " }\n", + " else if (method == \"minprob\") {\n", + " install_bioconductor(\"impute\")\n", + " install_bioconductor(\"pcaMethods\")\n", + " install_rpackage('imputeLCMD')\n", + " xxm <- as.matrix(df1)\n", + " df <-\n", + " imputeLCMD::impute.MinProb(xxm, q = 0.01, tune.sigma = 1)\n", + " }\n", + " else if (method == \"irm\") {\n", + " install_rpackage('VIM')\n", + " df <- irmi(df1, trace = TRUE, imp_var = FALSE)\n", + " rownames(df) <- rownames(df1)\n", + " }\n", + " else if (method == \"impseq\") {\n", + " install_rpackage('rrcovNA')\n", + " df <- impSeq(df1)\n", + " }\n", + " else if (method == \"impseqrob\") {\n", + " install_rpackage('rrcovNA')\n", + " data_zero1 <- impSeqRob(df1, alpha = 0.9)\n", + " df <- data_zero1$x\n", + " }\n", + " else if (method == \"mice-norm\") {\n", + " install_rpackage('mice')\n", + " minum <- 5\n", + " datareadmi <- mice(df1,\n", + " m = minum,\n", + " seed = 1234,\n", + " method = \"norm\")\n", + " newdatareadmi <- 0\n", + " for (i in 1:minum) {\n", + " newdatareadmi <- complete(datareadmi, action = i) + newdatareadmi\n", " }\n", - " else if(method==\"irm\"){\n", - " install_rpackage('VIM')\n", - " df <- irmi(df1, trace = TRUE,imp_var=FALSE)\n", - " rownames(df)<-rownames(df1)\n", + " df <- newdatareadmi / minum\n", + " rownames(df) <- rownames(df1)\n", + " }\n", + " else if (method == \"mice-cart\") {\n", + " install_rpackage('mice')\n", + " minum <- 5\n", + " datareadmi <- mice(df1,\n", + " m = minum,\n", + " seed = 1234,\n", + " method = \"cart\")\n", + " newdatareadmi <- 0\n", + " for (i in 1:minum) {\n", + " newdatareadmi <- complete(datareadmi, action = i) + newdatareadmi\n", " }\n", - " else if(method==\"impseq\"){\n", - " install_rpackage('rrcovNA')\n", - " df <- impSeq(df1)\n", - " }\n", - " else if(method==\"impseqrob\"){\n", - " install_rpackage('rrcovNA')\n", - " data_zero1 <- impSeqRob(df1, alpha=0.9)\n", - " df<-data_zero1$x\n", - " }\n", - " else if(method==\"mice-norm\"){\n", - " install_rpackage('mice')\n", - " minum<-5\n", - " datareadmi<-mice(df1,m=minum,seed = 1234, method =\"norm\")\n", - " newdatareadmi<-0\n", - " for (i in 1:minum) {\n", - " newdatareadmi<-complete(datareadmi,action = i)+newdatareadmi\n", - " }\n", - " df<-newdatareadmi/minum\n", - " rownames(df)<-rownames(df1)\n", - " }\n", - " else if(method==\"mice-cart\"){\n", - " install_rpackage('mice')\n", - " minum<-5\n", - " datareadmi<-mice(df1,m=minum,seed = 1234, method =\"cart\")\n", - " newdatareadmi<-0\n", - " for (i in 1:minum) {\n", - " newdatareadmi<-complete(datareadmi,action = i)+newdatareadmi\n", - " }\n", - " df<-newdatareadmi/minum\n", - " rownames(df)<-rownames(df1)\n", - " }\n", - " else if(method==\"trknn\"){\n", - " source('src/R_NAGuideR/Imput_funcs.r')\n", - " # sim_trKNN_wrapper <- function(data) {\n", - " # result <- data %>% as.matrix %>% t %>% imputeKNN(., k=10, distance='truncation', perc=0) %>% t\n", - " # return(result)\n", - " # }\n", - " # df1x <- sim_trKNN_wrapper(t(df1))\n", - " # df<-as.data.frame(t(df1x))\n", - " df <- imputeKNN(as.matrix(df), k=10, distance='truncation', perc=0)\n", - " df <- as.data.frame(df)\n", - " }\n", - " else if(method==\"rf\"){\n", - " install_rpackage(\"missForest\")\n", - " data_zero1 <- missForest(t(df1), maxiter =10,\n", - " ntree = 20 # input$rfntrees\n", - " ,mtry=floor(nrow(df1)^(1/3)),verbose = TRUE)\n", - " df<-t(data_zero1$ximp)\n", - " }\n", - " else if(method==\"pi\"){\n", - " width <- 0.3 # input$piwidth\n", - " downshift <- 1.8 # input$pidownshift\n", - " for(i in 1:ncol(df1)){\n", - " temp <- df1[[i]]\n", - " if(sum(is.na(temp))>0){\n", - " temp.sd <- width * sd(temp[!is.na(temp)], na.rm = TRUE)\n", - " temp.mean <- mean(temp[!is.na(temp)], na.rm = TRUE) - downshift * sd(temp[!is.na(temp)], na.rm = TRUE)\n", - " n.missing <- sum(is.na(temp))\n", - " temp[is.na(temp)] <- rnorm(n.missing, mean = temp.mean, sd = temp.sd)\n", - " df[[i]]<-temp\n", - " }\n", - " }\n", - " df\n", - " }\n", - " # else if(method==\"grr\"){\n", - " # library(DreamAI)\n", - " # df<-impute.RegImpute(data=as.matrix(df1), fillmethod = \"row_mean\", maxiter_RegImpute = 10,conv_nrmse = 1e-03)\n", + " df <- newdatareadmi / minum\n", + " rownames(df) <- rownames(df1)\n", + " }\n", + " else if (method == \"trknn\") {\n", + " source('src/R_NAGuideR/Imput_funcs.r')\n", + " # sim_trKNN_wrapper <- function(data) {\n", + " # result <- data %>% as.matrix %>% t %>% imputeKNN(., k=10, distance='truncation', perc=0) %>% t\n", + " # return(result)\n", " # }\n", - " else if(method==\"gms\"){\n", - " # install.packages('GMSimpute')\n", - " if(!require(GMSimpute)){\n", - " install.packages(\"src/R_NAGuideR/GMSimpute_0.0.1.1.tar.gz\", repos = NULL, type=\"source\");\n", - " library(GMSimpute)\n", + " # df1x <- sim_trKNN_wrapper(t(df1))\n", + " # df<-as.data.frame(t(df1x))\n", + " df <-\n", + " imputeKNN(as.matrix(df),\n", + " k = 10,\n", + " distance = 'truncation',\n", + " perc = 0)\n", + " df <- as.data.frame(df)\n", + " }\n", + " else if (method == \"rf\") {\n", + " install_rpackage(\"missForest\")\n", + " data_zero1 <- missForest(\n", + " t(df1),\n", + " maxiter = 10,\n", + " ntree = 20 # input$rfntrees\n", + " ,\n", + " mtry = floor(nrow(df1) ^ (1 / 3)),\n", + " verbose = TRUE\n", + " )\n", + " df <- t(data_zero1$ximp)\n", + " }\n", + " else if (method == \"pi\") {\n", + " width <- 0.3 # input$piwidth\n", + " downshift <- 1.8 # input$pidownshift\n", + " for (i in 1:ncol(df1)) {\n", + " temp <- df1[[i]]\n", + " if (sum(is.na(temp)) > 0) {\n", + " temp.sd <- width * sd(temp[!is.na(temp)], na.rm = TRUE)\n", + " temp.mean <-\n", + " mean(temp[!is.na(temp)], na.rm = TRUE) - downshift * sd(temp[!is.na(temp)], na.rm = TRUE)\n", + " n.missing <- sum(is.na(temp))\n", + " temp[is.na(temp)] <-\n", + " rnorm(n.missing, mean = temp.mean, sd = temp.sd)\n", + " df[[i]] <- temp\n", " }\n", - " \n", - " df<-GMS.Lasso(df1,nfolds=3,log.scale=FALSE,TS.Lasso=TRUE)\n", - " }\n", - " else if(method==\"msimpute\"){\n", - " install_bioconductor(\"msImpute\")\n", - " df <- msImpute(as.matrix(df), method='v2')\n", - " df <- as.data.frame(df) \n", " }\n", - " else{\n", - " stop(paste(\"Unspported methods so far: \", method))\n", + " df\n", + " }\n", + " # else if(method==\"grr\"){\n", + " # library(DreamAI)\n", + " # df<-impute.RegImpute(data=as.matrix(df1), fillmethod = \"row_mean\", maxiter_RegImpute = 10,conv_nrmse = 1e-03)\n", + " # }\n", + " else if (method == \"gms\") {\n", + " # install.packages('GMSimpute')\n", + " if (!require(GMSimpute)) {\n", + " install.packages(\n", + " \"src/R_NAGuideR/GMSimpute_0.0.1.1.tar.gz\",\n", + " repos = NULL,\n", + " type = \"source\"\n", + " )\n", + " \n", + " library(GMSimpute)\n", " }\n", + " \n", + " df <- GMS.Lasso(df1,\n", + " nfolds = 3,\n", + " log.scale = FALSE,\n", + " TS.Lasso = TRUE)\n", + " }\n", + " else if (method == \"msimpute\") {\n", + " install_bioconductor(\"msImpute\")\n", + " df <- msImpute(as.matrix(df), method = 'v2')\n", " df <- as.data.frame(df)\n", - " df\n", - " }" + " }\n", + " else{\n", + " stop(paste(\"Unspported methods so far: \", method))\n", + " }\n", + " df <- as.data.frame(df)\n", + " df\n", + "}" ] }, { @@ -325,7 +368,13 @@ }, "outputs": [], "source": [ - "df <- utils::read.csv(train_split, row.names=1, header=TRUE, stringsAsFactors = FALSE)\n", + "df <-\n", + " utils::read.csv(\n", + " train_split,\n", + " row.names = 1,\n", + " header = TRUE,\n", + " stringsAsFactors = FALSE\n", + " )\n", "df" ] }, @@ -352,9 +401,12 @@ }, "outputs": [], "source": [ - "original_header <- colnames(\n", - " readr::read_csv(train_split, n_max=1, col_names=TRUE, skip=0)\n", - ")\n", + "original_header <- colnames(readr::read_csv(\n", + " train_split,\n", + " n_max = 1,\n", + " col_names = TRUE,\n", + " skip = 0\n", + "))\n", "feat_name <- original_header[1]\n", "original_header[1:5]" ] @@ -379,30 +431,30 @@ "outputs": [], "source": [ "# to_test <- c(\n", - " # 'ZERO',\n", - " # 'MINIMUM',\n", - " # 'COLMEDIAN',\n", - " # 'ROWMEDIAN',\n", - " # 'KNN_IMPUTE',\n", - " # 'SEQKNN',\n", - " # 'BPCA',\n", - " # 'SVDMETHOD',\n", - " # 'LLS',\n", - " # 'MLE',\n", - " # 'LLS',\n", - " # 'QRILC',\n", - " # 'MINDET',\n", - " # 'MINPROB',\n", - " # 'IRM',\n", - " # 'IMPSEQ',\n", - " # 'IMPSEQROB',\n", - " # 'MICE-NORM',\n", - " # 'MICE-CART',\n", - " # 'RF',\n", - " # 'PI',\n", - " # 'GMS', # fails to install on Windows\n", - " # 'trknn',\n", - " # 'msimpute'\n", + "# 'ZERO',\n", + "# 'MINIMUM',\n", + "# 'COLMEDIAN',\n", + "# 'ROWMEDIAN',\n", + "# 'KNN_IMPUTE',\n", + "# 'SEQKNN',\n", + "# 'BPCA',\n", + "# 'SVDMETHOD',\n", + "# 'LLS',\n", + "# 'MLE',\n", + "# 'LLS',\n", + "# 'QRILC',\n", + "# 'MINDET',\n", + "# 'MINPROB',\n", + "# 'IRM',\n", + "# 'IMPSEQ',\n", + "# 'IMPSEQROB',\n", + "# 'MICE-NORM',\n", + "# 'MICE-CART',\n", + "# 'RF',\n", + "# 'PI',\n", + "# 'GMS', # fails to install on Windows\n", + "# 'trknn',\n", + "# 'msimpute'\n", "# )\n", "\n", "# for (method in to_test) {\n", @@ -433,9 +485,7 @@ "outputs": [], "source": [ "pred <- nafunctions(df, method)\n", - "pred <- tibble::as_tibble(\n", - " cbind(rownames(pred), pred)\n", - ")\n", + "pred <- tibble::as_tibble(cbind(rownames(pred), pred))\n", "names(pred) <- original_header\n", "pred" ] @@ -452,7 +502,7 @@ }, "outputs": [], "source": [ - "pred <- reshape2::melt(pred, id.vars=feat_name)\n", + "pred <- reshape2::melt(pred, id.vars = feat_name)\n", "names(pred) <- c(feat_name, 'Sample ID', method)\n", "pred <- pred[reshape2::melt(is.na(df))['value'] == TRUE, ]\n", "pred" @@ -483,7 +533,9 @@ }, "outputs": [], "source": [ - "fname = file.path(folder_experiment, 'preds', paste0('pred_all_', toupper(method), '.csv'))\n", + "fname = file.path(folder_experiment,\n", + " 'preds',\n", + " paste0('pred_all_', toupper(method), '.csv'))\n", "fname" ] }, @@ -498,7 +550,7 @@ }, "outputs": [], "source": [ - "write_csv(pred, path=fname)" + "write_csv(pred, path = fname)" ] } ], From ec85618b1de1508d58b84f5f3d760ba7b185c550 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 9 Nov 2023 13:25:19 +0100 Subject: [PATCH 43/70] :sparkles: Added GSIMP and MsImpute v2-mnar - developed locally -> up for testing if dependencies are met (GSIMP is no package and dependencies were figured out locally) - test in example workflow (-> GSimp did not finish locally) --- project/01_1_train_NAGuideR_methods.R | 85 ++++- project/01_1_train_NAGuideR_methods.ipynb | 85 ++++- .../single_dev_dataset/example/config.yaml | 3 +- project/src/R_NAGuideR/GSimp.R | 339 ++++++++++++++++++ 4 files changed, 501 insertions(+), 11 deletions(-) create mode 100644 project/src/R_NAGuideR/GSimp.R diff --git a/project/01_1_train_NAGuideR_methods.R b/project/01_1_train_NAGuideR_methods.R index d39d5d674..ce2f91af9 100644 --- a/project/01_1_train_NAGuideR_methods.R +++ b/project/01_1_train_NAGuideR_methods.R @@ -260,9 +260,75 @@ nafunctions <- function(x, method = "zero") { } else if (method == "msimpute") { install_bioconductor("msImpute") - df <- msImpute(as.matrix(df), method = 'v2') + df <- msImpute(as.matrix(df), + method = 'v2') df <- as.data.frame(df) } + else if (method == "msimpute_mnar") { + install_bioconductor("msImpute") + df <- + msImpute(as.matrix(df), + method = 'v2-mnar', + group = rep(1, dim(df)[2])) + df <- as.data.frame(df) + } + else if (method == "gsimp") { + options(stringsAsFactors = F) + # dependencies parly for sourced file + + install_bioconductor("impute") + install_bioconductor("pcaMethods") + install_rpackage('imputeLCMD') + install_rpackage("magrittr") + install_rpackage("glmnet") + install_rpackage("abind") + install_rpackage("foreach") + install_rpackage("doParallel") + source('src/R_NAGuideR/GSimp.R') + + # wrapper function with data pre-processing + pre_processing_GS_wrapper <- function(data_raw_log) { + # samples in rows, features in columns # + # Initialization # + data_raw_log_qrilc <- as.data.frame(data_raw_log) %>% + impute.QRILC() %>% extract2(1) + # Centralization and scaling # + data_raw_log_qrilc_sc <- + scale_recover(data_raw_log_qrilc, method = 'scale') + # Data after centralization and scaling # + data_raw_log_qrilc_sc_df <- data_raw_log_qrilc_sc[[1]] + # Parameters for centralization and scaling (for scaling recovery) # + data_raw_log_qrilc_sc_df_param <- data_raw_log_qrilc_sc[[2]] + # NA position # + NA_pos <- which(is.na(data_raw_log), arr.ind = T) + # NA introduced to log-scaled-initialized data # + data_raw_log_sc <- data_raw_log_qrilc_sc_df + data_raw_log_sc[NA_pos] <- NA + # Feed initialized and missing data into GSimp imputation # + result <- + data_raw_log_sc %>% GS_impute( + ., + iters_each = 50, + iters_all = 10, + initial = data_raw_log_qrilc_sc_df, + lo = -Inf, + hi = 'min', + n_cores = 1, + imp_model = 'glmnet_pred' + ) + data_imp_log_sc <- result$data_imp + # Data recovery # + data_imp <- data_imp_log_sc %>% + scale_recover(., method = 'recover', + param_df = data_raw_log_qrilc_sc_df_param) %>% + extract2(1) + return(data_imp) + } + df <- t(df) # samples in rows, feature in columns + df <- pre_processing_GS_wrapper(df) + df <- t(df) # features in rows, samples in columns + + } else{ stop(paste("Unspported methods so far: ", method)) } @@ -273,7 +339,9 @@ nafunctions <- function(x, method = "zero") { # ## Parameters # -# Choose one of the available methods. Some methods might fail for your dataset for unknown reasons (and the error won't always be easy to under) +# Choose one of the available methods. +# Some methods might fail for your dataset for unknown reasons +# (and the error won't always be easy to understand) # ```method # method = 'ZERO' # method = 'MINIMUM' @@ -297,6 +365,10 @@ nafunctions <- function(x, method = "zero") { # method = 'RF' # method = 'PI' # method = 'GMS' +# method = 'TRKNN', +# method = 'MSIMPUTE' +# method = 'MSIMPUTE_MNAR' +# method = 'GSIMP' # ``` # + tags=["parameters"] vscode={"languageId": "r"} @@ -319,7 +391,8 @@ df # - # - `data.frame` does not allow abritary column names, but only valid column names... -# - tibbles don't support rownames, and the imputation methods rely on normal `data.frame`s. Save the header row for later use. +# - tibbles don't support rownames, and the imputation methods rely on normal `data.frame`s. +# Save the header row for later use. # + vscode={"languageId": "r"} original_header <- colnames(readr::read_csv( @@ -358,8 +431,10 @@ original_header[1:5] # 'RF', # 'PI', # 'GMS', # fails to install on Windows -# 'trknn', -# 'msimpute' +# 'TRKNN', +# 'MSIMPUTE' +# 'MSIMPUTE_MNAR' +# 'GSIMP' # ) # for (method in to_test) { diff --git a/project/01_1_train_NAGuideR_methods.ipynb b/project/01_1_train_NAGuideR_methods.ipynb index fb6a72b19..072e207c2 100644 --- a/project/01_1_train_NAGuideR_methods.ipynb +++ b/project/01_1_train_NAGuideR_methods.ipynb @@ -284,9 +284,75 @@ " }\n", " else if (method == \"msimpute\") {\n", " install_bioconductor(\"msImpute\")\n", - " df <- msImpute(as.matrix(df), method = 'v2')\n", + " df <- msImpute(as.matrix(df),\n", + " method = 'v2')\n", " df <- as.data.frame(df)\n", " }\n", + " else if (method == \"msimpute_mnar\") {\n", + " install_bioconductor(\"msImpute\")\n", + " df <-\n", + " msImpute(as.matrix(df),\n", + " method = 'v2-mnar',\n", + " group = rep(1, dim(df)[2]))\n", + " df <- as.data.frame(df)\n", + " }\n", + " else if (method == \"gsimp\") {\n", + " options(stringsAsFactors = F)\n", + " # dependencies parly for sourced file\n", + " \n", + " install_bioconductor(\"impute\")\n", + " install_bioconductor(\"pcaMethods\")\n", + " install_rpackage('imputeLCMD')\n", + " install_rpackage(\"magrittr\")\n", + " install_rpackage(\"glmnet\")\n", + " install_rpackage(\"abind\")\n", + " install_rpackage(\"foreach\")\n", + " install_rpackage(\"doParallel\")\n", + " source('src/R_NAGuideR/GSimp.R')\n", + " \n", + " # wrapper function with data pre-processing\n", + " pre_processing_GS_wrapper <- function(data_raw_log) {\n", + " # samples in rows, features in columns #\n", + " # Initialization #\n", + " data_raw_log_qrilc <- as.data.frame(data_raw_log) %>%\n", + " impute.QRILC() %>% extract2(1)\n", + " # Centralization and scaling #\n", + " data_raw_log_qrilc_sc <-\n", + " scale_recover(data_raw_log_qrilc, method = 'scale')\n", + " # Data after centralization and scaling #\n", + " data_raw_log_qrilc_sc_df <- data_raw_log_qrilc_sc[[1]]\n", + " # Parameters for centralization and scaling (for scaling recovery) #\n", + " data_raw_log_qrilc_sc_df_param <- data_raw_log_qrilc_sc[[2]]\n", + " # NA position #\n", + " NA_pos <- which(is.na(data_raw_log), arr.ind = T)\n", + " # NA introduced to log-scaled-initialized data #\n", + " data_raw_log_sc <- data_raw_log_qrilc_sc_df\n", + " data_raw_log_sc[NA_pos] <- NA\n", + " # Feed initialized and missing data into GSimp imputation #\n", + " result <-\n", + " data_raw_log_sc %>% GS_impute(\n", + " .,\n", + " iters_each = 50,\n", + " iters_all = 10,\n", + " initial = data_raw_log_qrilc_sc_df,\n", + " lo = -Inf,\n", + " hi = 'min',\n", + " n_cores = 1,\n", + " imp_model = 'glmnet_pred'\n", + " )\n", + " data_imp_log_sc <- result$data_imp\n", + " # Data recovery #\n", + " data_imp <- data_imp_log_sc %>%\n", + " scale_recover(., method = 'recover',\n", + " param_df = data_raw_log_qrilc_sc_df_param) %>%\n", + " extract2(1)\n", + " return(data_imp)\n", + " }\n", + " df <- t(df) # samples in rows, feature in columns\n", + " df <- pre_processing_GS_wrapper(df)\n", + " df <- t(df) # features in rows, samples in columns\n", + " \n", + " }\n", " else{\n", " stop(paste(\"Unspported methods so far: \", method))\n", " }\n", @@ -302,7 +368,9 @@ "source": [ "## Parameters\n", "\n", - "Choose one of the available methods. Some methods might fail for your dataset for unknown reasons (and the error won't always be easy to under)\n", + "Choose one of the available methods. \n", + "Some methods might fail for your dataset for unknown reasons\n", + "(and the error won't always be easy to understand)\n", "```method\n", "method = 'ZERO'\n", "method = 'MINIMUM'\n", @@ -326,6 +394,10 @@ "method = 'RF'\n", "method = 'PI'\n", "method = 'GMS'\n", + "method = 'TRKNN',\n", + "method = 'MSIMPUTE'\n", + "method = 'MSIMPUTE_MNAR'\n", + "method = 'GSIMP'\n", "```" ] }, @@ -386,7 +458,8 @@ }, "source": [ "- `data.frame` does not allow abritary column names, but only valid column names...\n", - "- tibbles don't support rownames, and the imputation methods rely on normal `data.frame`s. Save the header row for later use." + "- tibbles don't support rownames, and the imputation methods rely on normal `data.frame`s.\n", + "Save the header row for later use." ] }, { @@ -453,8 +526,10 @@ "# 'RF',\n", "# 'PI',\n", "# 'GMS', # fails to install on Windows\n", - "# 'trknn',\n", - "# 'msimpute'\n", + "# 'TRKNN',\n", + "# 'MSIMPUTE'\n", + "# 'MSIMPUTE_MNAR'\n", + "# 'GSIMP'\n", "# )\n", "\n", "# for (method in to_test) {\n", diff --git a/project/config/single_dev_dataset/example/config.yaml b/project/config/single_dev_dataset/example/config.yaml index 432ac518d..ee15b19fe 100644 --- a/project/config/single_dev_dataset/example/config.yaml +++ b/project/config/single_dev_dataset/example/config.yaml @@ -23,4 +23,5 @@ NAGuideR_methods: - MLE # norm - IRM # VIM - ~9mins - TRKNN - - MSIMPUTE + - MSIMPUTE_MNAR + - GSIMP diff --git a/project/src/R_NAGuideR/GSimp.R b/project/src/R_NAGuideR/GSimp.R new file mode 100644 index 000000000..3346e5066 --- /dev/null +++ b/project/src/R_NAGuideR/GSimp.R @@ -0,0 +1,339 @@ +# formatted from https://github.com/WandeRum/GSimp/blob/9f661e5ebf991b160ccedb7728c5bcd825dc963b/GSimp.R +# require(missForest) +require(imputeLCMD) +require(magrittr) +require(glmnet) +require(abind) +require(foreach) +require(doParallel) +# require(MASS) + + +## Source ## +# source('MVI_global.R') +# source('Prediction_funcs.R') + +## Draw n samples from a truncated normal distribution N(mu, std^2|[lo, hi]) ## +rnorm_trunc <- function (n, + mu, + std, + lo = -Inf, + hi = Inf) { + p_lo <- pnorm(lo, mu, std) + p_hi <- pnorm(hi, mu, std) + p_hi[p_hi < .01] <- .01 + u <- runif(n, p_lo, p_hi) + return(qnorm(u, mu, std)) +} + +## Initialize the missing data ## +## lsym will draw samples from the right tail of the distribution and transformed to the left tail +miss_init <- + function(miss_data, + method = c('lsym', 'qrilc', 'rsym')[1]) { + init_data <- miss_data + if (method == 'lsym') { + for (i in 1:ncol(init_data)) { + col_temp <- init_data[, i] + na_idx <- which(is.na(col_temp)) + prop <- mean(is.na(col_temp)) + min_temp <- min(col_temp, na.rm = T) + col_temp[na_idx] <- min_temp - 1 + med_temp <- median(col_temp) + col_temp[na_idx] <- + med_temp - (sample(col_temp[col_temp >= quantile(col_temp, 1 - prop)], length(na_idx), replace = + T) - med_temp) + init_data[, i] <- col_temp + } + } + if (method == 'rsym') { + for (i in 1:ncol(init_data)) { + col_temp <- init_data[, i] + na_idx <- which(is.na(col_temp)) + prop <- mean(is.na(col_temp)) + max_temp <- max(col_temp, na.rm = T) + col_temp[na_idx] <- max_temp + 1 + med_temp <- median(col_temp) + col_temp[na_idx] <- + med_temp + (med_temp - sample(col_temp[col_temp <= quantile(col_temp, prop)], length(na_idx), replace = + T)) + init_data[, i] <- col_temp + } + } + if (method == 'qrilc') { + init_data <- impute.QRILC(miss_data)[[1]] + } + return(init_data) + } + +## Single missing variable imputation based on Gibbs sampler ## +single_impute_iters <- + function(x, + y, + y_miss, + y_real = NULL, + imp_model = 'glmnet_pred', + lo = -Inf, + hi = Inf, + iters_each = 100, + gibbs = c()) { + y_res <- y + x <- as.matrix(x) + na_idx <- which(is.na(y_miss)) + imp_model_func <- getFunction(imp_model) + nrmse_vec <- c() + gibbs_res <- array(NA, dim = c(3, length(gibbs), iters_each)) + dimnames(gibbs_res) <- list(c('std', 'yhat', 'yres'), NULL, NULL) + + for (i in 1:iters_each) { + y_hat <- imp_model_func(x, y_res) + std <- sqrt(sum((y_hat[na_idx] - y_res[na_idx]) ^ 2) / length(na_idx)) + y_res[na_idx] <- + rnorm_trunc(length(na_idx), y_hat[na_idx], std, lo, hi) + if (length(gibbs) > 0) { + gibbs_res[1, , i] <- std + gibbs_res[2, , i] <- y_hat[gibbs] + gibbs_res[3, , i] <- y_res[gibbs] + } + ## The following code is for prediction function testing when y_real availabe ## + if (!is.null(y_real)) { + Sys.sleep(.5) + par(mfrow = c(2, 2)) + nrmse_vec <- c(nrmse_vec, nrmse(y_res, y_miss, y_real)) + plot(y_real ~ y_res) + plot(y_real ~ y_hat) + plot(y_hat ~ y_res) + plot(nrmse_vec) + } + } + return(list(y_imp = y_res, gibbs_res = gibbs_res)) + } + + +## Multiple missing variables imputation ## +## iters_each=number (100); vector of numbers, e.g. rep(100, 20) while iters_all=20 +## lo/hi=numer; vector; functions like min/max/median/mean... +## initial=character ('qrilc'/'lysm'); initialized data maatrix +## n_cores=1 is sequentially (non-parallel) computing +multi_impute <- + function(data_miss, + iters_each = 100, + iters_all = 20, + initial = 'qrilc', + lo = -Inf, + hi = 'min', + n_cores = 1, + imp_model = 'glmnet_pred', + gibbs = data.frame(row = integer(), col = integer())) { + ## Convert to data.frame ## + data_miss %<>% data.frame() + + ## Make vector for iters_each ## + if (length(iters_each) == 1) { + iters_each <- rep(iters_each, iters_all) + } else if (length(iters_each) == iters_all) { + iters_each <- iters_each + } else { + stop('improper argument: iters_each') + } + + + ## Missing count in each column ## + miss_count <- data_miss %>% apply(., 2, function(x) + sum(is.na(x))) + ## Index of missing variables, sorted (increasing) by the number of missings + miss_col_idx <- + order(miss_count, decreasing = T) %>% extract(1:sum(miss_count != 0)) %>% rev() + + if (!all(gibbs$col %in% miss_col_idx)) { + stop('improper argument: gibbs') + } + gibbs_sort <- gibbs + if (nrow(gibbs_sort) > 0) { + gibbs_sort$order <- c(1:nrow(gibbs_sort)) + gibbs_sort <- gibbs_sort[order(gibbs_sort$row),] + gibbs_sort <- + gibbs_sort[order(match(gibbs_sort$col, miss_col_idx)),] + } else { + gibbs_sort$order <- integer() + } + + ## Make vectors for lo and hi ## + if (length(lo) > 1) { + if (length(lo) != ncol(data_miss)) { + stop('Length of lo should equal to one or the number of variables') + } + else { + lo_vec <- lo + } + } else if (is.numeric(lo)) { + lo_vec <- rep(lo, ncol(data_miss)) + } else if (is.character(lo)) { + lo_fun <- getFunction(lo) + lo_vec <- + apply(data_miss, 2, function(x) + x %>% na.omit %>% lo_fun) + } + + if (length(hi) > 1) { + if (length(hi) != ncol(data_miss)) { + stop('Length of hi should equal to one or the number of variables') + } + else { + hi_vec <- hi + } + } else if (is.numeric(hi)) { + hi_vec <- rep(hi, ncol(data_miss)) + } else if (is.character(hi)) { + hi_fun <- getFunction(hi) + hi_vec <- + apply(data_miss, 2, function(x) + x %>% na.omit %>% hi_fun) + } + + # Check whether lo is lower than hi + if (!all(lo_vec < hi_vec)) { + stop('lo should be lower than hi') + } + + ## Initialization using build-in method or input initial matrix ## + if (is.character(initial)) { + data_init <- miss_init(data_miss, method = initial) + } else if (is.data.frame(initial) & + identical(data_miss[!is.na(data_miss)], initial[!is.na(data_miss)])) { + data_init <- initial + } else { + stop('improper argument: initial') + } + + data_imp <- data_init + gibbs_res_final <- array(NA, dim = c(3, nrow(gibbs), 0)) + + ## Iterations for the whole data matrix ## + for (i in 1:iters_all) { + cat('Iteration', i, 'start...') + + ## Parallel computing ## + if (n_cores > 1) { + cat(paste0('Parallel computing (n_cores=', n_cores, ')...')) + ## Parallel on missing variables + cl <- makeCluster(n_cores) + registerDoParallel(cl) + core_res <- + foreach ( + k = miss_col_idx, + .combine = 'cbind_abind', + .export = c('single_impute_iters', 'rnorm_trunc'), + .packages = c('magrittr') + ) %dopar% { + source('Prediction_funcs.R') + gibbs_sort_temp <- gibbs_sort[gibbs_sort$col == k,] + y_imp_res <- + single_impute_iters( + data_imp[,-k], + data_imp[, k], + data_miss[, k], + imp_model = imp_model, + lo = lo_vec[k], + hi = hi_vec[k], + iters_each = iters_each[i], + gibbs = gibbs_sort_temp$row + ) + y_imp_df <- y_imp_res$y_imp %>% data.frame + colnames(y_imp_df) <- colnames(data_miss)[k] + gibbs_res <- y_imp_res$gibbs_res + list(y_imp = y_imp_df, gibbs_res = gibbs_res) + } + stopCluster(cl) + y_imp_df <- core_res$y_imp + gibbs_res_final <- + abind(gibbs_res_final, core_res$gibbs_res, along = 3) + miss_col_idx_match <- + match(colnames(y_imp_df), colnames(data_miss)) + data_imp[, miss_col_idx_match] <- y_imp_df + } else { + ## Sequential computing ## + gibbs_res_j <- array(NA, dim = c(3, 0, iters_each[i])) + for (j in miss_col_idx) { + gibbs_sort_temp <- gibbs_sort[gibbs_sort$col == j,] + y_miss <- data_miss[, j] + y_imp_res <- + single_impute_iters( + data_imp[,-j], + data_imp[, j], + y_miss, + imp_model = imp_model, + lo = lo_vec[j], + hi = hi_vec[j], + iters_each = iters_each[i], + gibbs = gibbs_sort_temp$row + ) + y_imp <- y_imp_res$y_imp + gibbs_res_j <- + abind(gibbs_res_j, y_imp_res$gibbs_res, along = 2) + data_imp[is.na(y_miss), j] <- y_imp[is.na(y_miss)] + } + gibbs_res_final <- + abind(gibbs_res_final, gibbs_res_j, along = 3) + } + cat('end!\n') + } + gibbs_res_final_reorder <- gibbs_res_final[, gibbs_sort$order,] + return(list(data_imp = data_imp, gibbs_res = gibbs_res_final_reorder)) + } + + +# GS_impute --------------------------------------------------------------- +GS_impute <- multi_impute + +# ------------------------------------------------------------------------------ + +# GSimp: MVI_global.R +# https://github.com/WandeRum/GSimp/blob/9f661e5ebf991b160ccedb7728c5bcd825dc963b/MVI_global.R#L41-L61 + +# Scale and recover ------------------------------------------------------- +scale_recover <- function(data, + method = 'scale', + param_df = NULL) { + results <- list() + data_res <- data + if (!is.null(param_df)) { + if (method == 'scale') { + data_res[] <- scale(data, center = param_df$mean, scale = param_df$std) + } else if (method == 'recover') { + data_res[] <- t(t(data) * param_df$std + param_df$mean) + } + } else { + if (method == 'scale') { + param_df <- + data.frame(mean = sapply(data, function(x) + mean(x, na.rm = T)), + std = sapply(data, function(x) + sd(x, na.rm = T))) + data_res[] <- + scale(data, center = param_df$mean, scale = param_df$std) + } else { + stop('no param_df found for recover...') + } + } + results[[1]] <- data_res + results[[2]] <- param_df + return(results) +} + + +# ------------------------------------------------------------------------------ +# https://github.com/WandeRum/GSimp/blob/9f661e5ebf991b160ccedb7728c5bcd825dc963b/Prediction_funcs.R#L27C1-L32C2 +# Prediction_funcs.R + +glmnet_pred <- function(x, y, alpha = .5, lambda = .01) { + x_mat <- as.matrix(x) + model <- glmnet( + x = x_mat, + y = y, + alpha = alpha, + lambda = lambda + ) + y_hat <- predict(model, newx = x_mat)[, 1] + return(y_hat) +} From 7a557671771bb60dbfc078cb842e0ecc46121905 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Sat, 11 Nov 2023 15:06:58 +0100 Subject: [PATCH 44/70] :sparkles: log papermill output for each job - create individual logs for nb execution -> separate files on local execution -> documentation of how long training step took --- project/workflow/Snakefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/project/workflow/Snakefile b/project/workflow/Snakefile index f68f37f3b..b44af213d 100644 --- a/project/workflow/Snakefile +++ b/project/workflow/Snakefile @@ -120,6 +120,8 @@ rule train_NAGuideR_model: folder_experiment="{folder_experiment}", method="{method}", name="{method}", + log: + err="{folder_experiment}/01_1_train_NAGuideR_{method}.log" conda: "vaep" shell: @@ -127,6 +129,7 @@ rule train_NAGuideR_model: " -r train_split {input.train_split}" " -r method {params.method}" " -r folder_experiment {params.folder_experiment}" + " 2> {log.err}" " && jupyter nbconvert --to html {output.nb}" @@ -168,6 +171,8 @@ rule train_models: err="{folder_experiment}/01_1_train_{model}.e", out="{folder_experiment}/01_1_train_{model}.o", name="{model}", + log: + err="{folder_experiment}/01_1_train_{model}.log" conda: "vaep" shell: @@ -176,6 +181,7 @@ rule train_models: " -r folder_experiment {params.folder_experiment}" " -p fn_rawfile_metadata {params.meta_data}" " -r model_key {wildcards.model}" + " 2> {log.err}" " && jupyter nbconvert --to html {output.nb}" From 8bd3211fec9e8f96e46d4424119e0e49590751ba Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Sat, 11 Nov 2023 15:42:24 +0100 Subject: [PATCH 45/70] :bug: None is not dumped as null without cp dict - config dict has to be copied. Otherwise value None is not dumped as null: Before: - column_names: "None" Now: - column_names: null --- project/workflow/Snakefile_v2 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/project/workflow/Snakefile_v2 b/project/workflow/Snakefile_v2 index 90807c8ac..bbd2a95b7 100644 --- a/project/workflow/Snakefile_v2 +++ b/project/workflow/Snakefile_v2 @@ -251,7 +251,10 @@ rule dump_split_config: configfile=config["config_split"], run: import yaml - + # recreating dict, otherwise Null becomes string "Null" in yaml dump... + cfg = dict() + for k, v in config["split_data"].items(): + cfg[k] = v with open(output.configfile, "w") as f: - f.write("# Build in Snakemake workflow\n") - yaml.dump(config["split_data"], f, sort_keys=False) + f.write("# Build in Snakemake workflow (from v2)\n") + yaml.dump(cfg, f, sort_keys=False) From d0155179706b24b621b5e6a2b8eedfa5c081cb00 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 14 Nov 2023 14:54:32 +0100 Subject: [PATCH 46/70] :bug: Quote strings to allow white spaces in folder names --- project/workflow/Snakefile | 48 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/project/workflow/Snakefile b/project/workflow/Snakefile index b44af213d..41228991f 100644 --- a/project/workflow/Snakefile +++ b/project/workflow/Snakefile @@ -57,11 +57,11 @@ rule comparison: err=f"{{folder_experiment}}/{nb_stem}.e", out=f"{{folder_experiment}}/{nb_stem}.o", shell: - "papermill {input.nb} {output.nb}" + "papermill {input.nb} {output.nb:q}" " -r fn_rawfile_metadata {params.meta_data:q}" " -r folder_experiment {wildcards.folder_experiment:q}" " -r models {params.models:q}" - " && jupyter nbconvert --to html {output.nb}" + " && jupyter nbconvert --to html {output.nb:q}" ########################################################################################## @@ -95,10 +95,10 @@ rule transform_NAGuideR_predictions: # https://snakemake.readthedocs.io/en/stable/snakefiles/rules.html#non-file-parameters-for-rules dumps_as_str=lambda wildcards, input: ",".join(input.dumps), shell: - "papermill {input.nb} {output.nb}" - " -r folder_experiment {params.folder_experiment}" + "papermill {input.nb} {output.nb:q}" + " -r folder_experiment {params.folder_experiment:q}" " -p dumps {params.dumps_as_str}" - " && jupyter nbconvert --to html {output.nb}" + " && jupyter nbconvert --to html {output.nb:q}" rule train_NAGuideR_model: @@ -121,16 +121,16 @@ rule train_NAGuideR_model: method="{method}", name="{method}", log: - err="{folder_experiment}/01_1_train_NAGuideR_{method}.log" + err="{folder_experiment}/01_1_train_NAGuideR_{method}.log", conda: "vaep" shell: - "papermill {input.nb} {output.nb}" - " -r train_split {input.train_split}" + "papermill {input.nb} {output.nb:q}" + " -r train_split {input.train_split:q}" " -r method {params.method}" - " -r folder_experiment {params.folder_experiment}" + " -r folder_experiment {params.folder_experiment:q}" " 2> {log.err}" - " && jupyter nbconvert --to html {output.nb}" + " && jupyter nbconvert --to html {output.nb:q}" nb_stem = "01_0_transform_data_to_wide_format" @@ -148,9 +148,9 @@ rule transform_data_to_wide_format: err=f"{{folder_experiment}}/{nb_stem}.e", out=f"{{folder_experiment}}/{nb_stem}.o", shell: - "papermill {input.nb} {output.nb}" - " -r folder_experiment {params.folder_experiment}" - " && jupyter nbconvert --to html {output.nb}" + "papermill {input.nb} {output.nb:q}" + " -r folder_experiment {params.folder_experiment:q}" + " && jupyter nbconvert --to html {output.nb:q}" ########################################################################################## @@ -172,17 +172,17 @@ rule train_models: out="{folder_experiment}/01_1_train_{model}.o", name="{model}", log: - err="{folder_experiment}/01_1_train_{model}.log" + err="{folder_experiment}/01_1_train_{model}.log", conda: "vaep" shell: - "papermill {input.nb} {output.nb}" - " -f {input.configfile}" - " -r folder_experiment {params.folder_experiment}" - " -p fn_rawfile_metadata {params.meta_data}" - " -r model_key {wildcards.model}" + "papermill {input.nb:q} {output.nb:q}" + " -f {input.configfile:q}" + " -r folder_experiment {params.folder_experiment:q}" + " -r fn_rawfile_metadata {params.meta_data:q}" + " -r model_key {wildcards.model:q}" " 2> {log.err}" - " && jupyter nbconvert --to html {output.nb}" + " && jupyter nbconvert --to html {output.nb:q}" ########################################################################################## @@ -205,7 +205,7 @@ rule create_splits: out=f"{{folder_experiment}}/{nb_stem}.o", shell: "papermill {input.nb} {output.nb}" - " -f {input.configfile}" - " -r folder_experiment {params.folder_experiment}" - " -p fn_rawfile_metadata {params.meta_data}" - " && jupyter nbconvert --to html {output.nb}" + " -f {input.configfile:q}" + " -r folder_experiment {params.folder_experiment:q}" + " -p fn_rawfile_metadata {params.meta_data:q}" + " && jupyter nbconvert --to html {output.nb:q}" From 139c792dca9f18b6e5aa5eb6478e62db940c5c1a Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 14 Nov 2023 15:08:41 +0100 Subject: [PATCH 47/70] :bug: few features have less than 4 training observations - one or two features have with 50 samples less than 4 intensities in training data split -> move the validation data for these to the training split --- project/01_0_split_data.ipynb | 60 ++++++++++++++++++++++++++--------- project/01_0_split_data.py | 43 ++++++++++++++++++------- 2 files changed, 76 insertions(+), 27 deletions(-) diff --git a/project/01_0_split_data.ipynb b/project/01_0_split_data.ipynb index ed62a0e31..753ce25a6 100644 --- a/project/01_0_split_data.ipynb +++ b/project/01_0_split_data.ipynb @@ -28,7 +28,7 @@ "\n", "import vaep\n", "from vaep.io.datasplits import DataSplits\n", - "from vaep.sampling import feature_frequency, sample_data\n", + "from vaep.sampling import feature_frequency\n", "\n", "from vaep.analyzers import analyzers\n", "from vaep.analyzers.analyzers import AnalyzePeptides\n", @@ -245,7 +245,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In case there are multiple features for each intensity values (currenlty: peptide sequence and charge), combine the column names to a single str index.\n", + "In case there are multiple features for each intensity values (currenlty: peptide sequence and charge),\n", + "combine the column names to a single str index.\n", "\n", "> The Collaborative Modeling approach will need a single feature column." ] @@ -290,7 +291,7 @@ "if params.fn_rawfile_metadata:\n", " df_meta = pd.read_csv(params.fn_rawfile_metadata, index_col=0)\n", "else:\n", - " logger.warning(f\"No metadata for samples provided, create placeholder.\")\n", + " logger.warning(\"No metadata for samples provided, create placeholder.\")\n", " if params.meta_date_col:\n", " raise ValueError(\n", " f\"No metadata provided, but data column set: {params.meta_date_col}\")\n", @@ -346,7 +347,8 @@ "if params.min_RT_time:\n", " logger.info(\n", " \"Metadata should have 'MS max RT' entry from ThermoRawFileParser\")\n", - " msg = f\"Minimum RT time maxiumum is set to {params.min_RT_time} minutes (to exclude too short runs, which are potentially fractions).\"\n", + " msg = (f\"Minimum RT time maxiumum is set to {params.min_RT_time} minutes\"\n", + " \" (to exclude too short runs, which are potentially fractions).\")\n", " # can be integrated into query string\n", " mask_RT = df_meta['MS max RT'] >= params.min_RT_time\n", " msg += f\" Total number of samples retained: {int(mask_RT.sum())}\"\n", @@ -598,7 +600,7 @@ "outputs": [], "source": [ "ax = df.notna().sum(axis=0).sort_values().plot()\n", - "_new_labels = [l.get_text().split(';')[0] for l in ax.get_xticklabels()]\n", + "_new_labels = [l_.get_text().split(';')[0] for l_ in ax.get_xticklabels()]\n", "_ = ax.set_xticklabels(_new_labels, rotation=45,\n", " horizontalalignment='right')\n", "ax.set_xlabel('feature prevalence')\n", @@ -1000,13 +1002,6 @@ "outputs": [], "source": [ "group = 2\n", - "# if not mnar:\n", - "# fake_na, splits.train_X = sample_data(df_long.squeeze(),\n", - "# sample_index_to_drop=0,\n", - "# weights=freq_per_feature,\n", - "# frac=0.1,\n", - "# random_state=params.random_state,)\n", - "# assert len(splits.train_X) > len(fake_na)\n", "! move parameter checks to start of script\n", "if 0.0 <= params.frac_mnar <= 1.0:\n", " fig, axes = plt.subplots(1, 2, figsize=(8, 2))\n", @@ -1146,9 +1141,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "lines_to_next_cell": 2 - }, + "metadata": {}, "outputs": [], "source": [ "diff = (splits\n", @@ -1168,6 +1161,43 @@ "diff" ] }, + { + "cell_type": "markdown", + "id": "b364b6a4", + "metadata": {}, + "source": [ + "Some tools require at least 4 observation in the training data,\n", + "which is a good requirment. Due to \"MNAR\" sampling, most measurments\n", + "of a features can end up in the validation or test data.\n", + "\n", + "In that case: Move the validation measurments back to the training data.\n", + "If after this procedure the condition is still not met, a value error is raised." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39b38235", + "metadata": {}, + "outputs": [], + "source": [ + "mask_min_4_measurments = splits.train_X.groupby(level=1).count() < 4\n", + "if mask_min_4_measurments.any():\n", + " idx = mask_min_4_measurments.loc[mask_min_4_measurments].index\n", + " logger.warning(f\"Features with less than 4 measurments in training data: {idx.to_list()}\")\n", + " to_remove = splits.val_y.loc[pd.IndexSlice[:, idx]]\n", + " print(\"To remove from validation data: \")\n", + " display(to_remove)\n", + " splits.train_X = pd.concat([splits.train_X, to_remove])\n", + " splits.val_y = splits.val_y.drop(to_remove.index)\n", + " # check condition again\n", + " mask_min_4_measurments = splits.train_X.groupby(level=1).count() < 4\n", + " if mask_min_4_measurments.any():\n", + " idx = mask_min_4_measurments.loc[mask_min_4_measurments].index\n", + " raise ValueError(\"Some features still have less than 4 measurments in training data\"\n", + " f\" after removing the features from the validation data: {idx.to_list()}\")" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/project/01_0_split_data.py b/project/01_0_split_data.py index fc41e698f..50939fb9c 100644 --- a/project/01_0_split_data.py +++ b/project/01_0_split_data.py @@ -32,7 +32,7 @@ import vaep from vaep.io.datasplits import DataSplits -from vaep.sampling import feature_frequency, sample_data +from vaep.sampling import feature_frequency from vaep.analyzers import analyzers from vaep.analyzers.analyzers import AnalyzePeptides @@ -174,7 +174,8 @@ def add_meta_data(df: pd.DataFrame, df_meta: pd.DataFrame): # %% [markdown] -# In case there are multiple features for each intensity values (currenlty: peptide sequence and charge), combine the column names to a single str index. +# In case there are multiple features for each intensity values (currenlty: peptide sequence and charge), +# combine the column names to a single str index. # # > The Collaborative Modeling approach will need a single feature column. @@ -203,7 +204,7 @@ def join_as_str(seq): if params.fn_rawfile_metadata: df_meta = pd.read_csv(params.fn_rawfile_metadata, index_col=0) else: - logger.warning(f"No metadata for samples provided, create placeholder.") + logger.warning("No metadata for samples provided, create placeholder.") if params.meta_date_col: raise ValueError( f"No metadata provided, but data column set: {params.meta_date_col}") @@ -236,7 +237,8 @@ def join_as_str(seq): if params.min_RT_time: logger.info( "Metadata should have 'MS max RT' entry from ThermoRawFileParser") - msg = f"Minimum RT time maxiumum is set to {params.min_RT_time} minutes (to exclude too short runs, which are potentially fractions)." + msg = (f"Minimum RT time maxiumum is set to {params.min_RT_time} minutes" + " (to exclude too short runs, which are potentially fractions).") # can be integrated into query string mask_RT = df_meta['MS max RT'] >= params.min_RT_time msg += f" Total number of samples retained: {int(mask_RT.sum())}" @@ -378,7 +380,7 @@ def join_as_str(seq): # %% ax = df.notna().sum(axis=0).sort_values().plot() -_new_labels = [l.get_text().split(';')[0] for l in ax.get_xticklabels()] +_new_labels = [l_.get_text().split(';')[0] for l_ in ax.get_xticklabels()] _ = ax.set_xticklabels(_new_labels, rotation=45, horizontalalignment='right') ax.set_xlabel('feature prevalence') @@ -608,13 +610,6 @@ def join_as_str(seq): # %% group = 2 -# if not mnar: -# fake_na, splits.train_X = sample_data(df_long.squeeze(), -# sample_index_to_drop=0, -# weights=freq_per_feature, -# frac=0.1, -# random_state=params.random_state,) -# assert len(splits.train_X) > len(fake_na) # ! move parameter checks to start of script if 0.0 <= params.frac_mnar <= 1.0: fig, axes = plt.subplots(1, 2, figsize=(8, 2)) @@ -743,6 +738,30 @@ def join_as_str(seq): splits.test_y = splits.test_y.drop(to_remove.index) diff +# %% [markdown] +# Some tools require at least 4 observation in the training data, +# which is a good requirment. Due to "MNAR" sampling, most measurments +# of a features can end up in the validation or test data. +# +# In that case: Move the validation measurments back to the training data. +# If after this procedure the condition is still not met, a value error is raised. + +# %% +mask_min_4_measurments = splits.train_X.groupby(level=1).count() < 4 +if mask_min_4_measurments.any(): + idx = mask_min_4_measurments.loc[mask_min_4_measurments].index + logger.warning(f"Features with less than 4 measurments in training data: {idx.to_list()}") + to_remove = splits.val_y.loc[pd.IndexSlice[:, idx]] + print("To remove from validation data: ") + display(to_remove) + splits.train_X = pd.concat([splits.train_X, to_remove]) + splits.val_y = splits.val_y.drop(to_remove.index) + # check condition again + mask_min_4_measurments = splits.train_X.groupby(level=1).count() < 4 + if mask_min_4_measurments.any(): + idx = mask_min_4_measurments.loc[mask_min_4_measurments].index + raise ValueError("Some features still have less than 4 measurments in training data" + f" after removing the features from the validation data: {idx.to_list()}") # %% [markdown] # ### Save in long format From 296cbf9628291ad186f7254b916cfea5728d95c5 Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 15 Nov 2023 16:36:53 +0100 Subject: [PATCH 48/70] :bug: GSIMP slow, SEQKNN does not like too few features - new dataset balancing between GSIMP runtime and SEQKNN need for a minimum number of features - run each method one by one (avoid race conditions when installing, only a problem on first time setup) --- .../single_dev_dataset/example/config.yaml | 2 +- .../single_dev_dataset/example/split.yaml | 5 +- .../protein_groups_wide_N50_M227.csv | 51 +++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 project/data/dev_datasets/HeLa_6070/protein_groups_wide_N50_M227.csv diff --git a/project/config/single_dev_dataset/example/config.yaml b/project/config/single_dev_dataset/example/config.yaml index ee15b19fe..649d702b4 100644 --- a/project/config/single_dev_dataset/example/config.yaml +++ b/project/config/single_dev_dataset/example/config.yaml @@ -24,4 +24,4 @@ NAGuideR_methods: - IRM # VIM - ~9mins - TRKNN - MSIMPUTE_MNAR - - GSIMP + - GSIMP # slow even on data with fewer features diff --git a/project/config/single_dev_dataset/example/split.yaml b/project/config/single_dev_dataset/example/split.yaml index 32672a3ba..85e8faaef 100644 --- a/project/config/single_dev_dataset/example/split.yaml +++ b/project/config/single_dev_dataset/example/split.yaml @@ -1,8 +1,9 @@ -FN_INTENSITIES: data/dev_datasets/HeLa_6070/protein_groups_wide_N50.csv +FN_INTENSITIES: data/dev_datasets/HeLa_6070/protein_groups_wide_N50_M227.csv fn_rawfile_metadata: data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv sample_completeness: 0.5 +feat_prevalence: 0.6 min_RT_time: 120 column_names: - Gene Names index_col: 0 -meta_date_col: Content Creation Date \ No newline at end of file +meta_date_col: Content Creation Date diff --git a/project/data/dev_datasets/HeLa_6070/protein_groups_wide_N50_M227.csv b/project/data/dev_datasets/HeLa_6070/protein_groups_wide_N50_M227.csv new file mode 100644 index 000000000..3f9a79c48 --- /dev/null +++ b/project/data/dev_datasets/HeLa_6070/protein_groups_wide_N50_M227.csv @@ -0,0 +1,51 @@ +Sample ID,NOP16,PTGES,WAC,CRNKL1,RPL18A,LPGAT1,PTGES3L-AARSD1;AARSD1,PPP1R2;PPP1R2P3,TOE1,FRG1,ALDH1A3,RPL36A;RPL36A-HNRNPH2,FBXO22,YIF1A,CEP55,DNAJC11,RARS2,QKI,DHX9,AGK,LRRC40,LIMD1,ALDOA,SOAT1,DIAPH1,CTH,SPRYD4,CD3EAP,NUP37,ARMC1,ATP2A2,EPB41L2,ATIC,CHORDC1,IQGAP1,ERMP1,LIMA1,C8orf82,COPG1,MDH2,C9orf78,TMA16,RPS10,H3F3B;H3F3A,XPA,MDC1,SORBS2,RCC2,RPL7A,DYNC1H1,LASP1,BOP1,ARMCX3,S100A10,NUP98,MRFAP1,BCAS2,NUDCD3,APEX1,S100A13,TEX10,RPS5,C15orf40,PIGK,COL14A1,EGFR,GGCT,ATXN10,SARS,KIF22,RABEPK,COG5,PGRMC2,RPS14,SDCBP,ZNF622,ST13;ST13P5;ST13P4,COMMD4,GPAA1,DNAJC10,RAD21,POLE4,AHSA1,SNAP29,HIST1H4A,POLR3E,NUDT9,MRPL3,DIMT1,MXRA7,UFL1,MARCH5,PBDC1,UBE3A,RPL29,SUMO2,PPIH,TIMELESS,ACOT7,TAMM41,SLC25A12,CNN3,PSMB5,SERPINB6,RPL27,MMTAG2,NOL6,RAD23B,LAMP1,ITPRIP,TCEB1,SLC35A4,COPE,PSMC6,NDUFA6,SSFA2,CEP170,HNRNPU,TP53RK,ZNF593,GAPDH,PPP2CB,PPP1CB,USP5,PON2,TNPO2,C2orf49,EWSR1,IDI1,NCAPD2,DNAAF5,SLC16A1,GTF3C3,NUCB2;Nucb2,IDH2,UBLCP1,INCENP,RAP2C,SCO2,SUN1,TPX2,LARS2,BZW1,MRPS36,OCIAD2,ATAD2,DPH2,CHMP1A,MYL6B,PITHD1,TMX1,TRMT61A,TKT,RRP36,APRT,FAHD1,CARKD,NCKAP1,NLN,MAPKAPK2,WDR55,SEC23A,EDC4,SLC7A1,LYRM2,CHTOP,XAB2,METTL5,CCDC59,EXOSC9,FERMT2,DHCR7,DCTPP1,HMGN4,FTO,RPAP3,URB2,VPS35,CDC73,DHX37,NARS,STX12,DCTN5,ZNF512,U2AF1,RPL3,RPAP1,FH,FKBP9,EIF2B5,ESF1,FHOD1,H2AFX;HIST1H2AA,TIMMDC1,PPP2R2A,BST2,NDUFS4,SAE1,MED1,MYCBP2,DIAPH3,EIF3J,AAMP,GCLC,PQBP1,CSTF3,NACC1,PARP4,UNC13D,ADSL,RPS17,ECHS1,LSM2,GPX4,OTUD6B,SEL1L,MACROD1,RRAS2,ACTR2,TOMM34,RAB5A,ROR2,XPOT,KPNA2,SBNO1,AUP1,TMSB4X +2019_12_18_14_35_Q-Exactive-HF-X-Orbitrap_6070,316880000.0,218380000.0,42243000.0,137700000.0,3703500000.0,,274590000.0,165980000.0,123170000.0,47520000.0,,,232390000.0,,26628000.0,106600000.0,24513000.0,131740000.0,12530000000.0,283670000.0,245040000.0,66667000.0,26334000000.0,1810500000.0,1604400000.0,57433000.0,44031000.0,105410000.0,262160000.0,106410000.0,3306700000.0,1352400000.0,4352000000.0,3007000000.0,8299800000.0,69639000.0,630990000.0,11403000.0,2104700000.0,8193700000.0,397820000.0,148580000.0,6289900000.0,,13925000.0,185210000.0,7592400.0,1554800000.0,9229200000.0,9173700000.0,2002500000.0,516460000.0,,621120000.0,954820000.0,92938000.0,496410000.0,149270000.0,3389000000.0,542700000.0,505810000.0,9974800000.0,27364000.0,25643000.0,,241660000.0,692400000.0,180070000.0,807330000.0,90161000.0,154720000.0,94128000.0,410570000.0,4921000000.0,67315000.0,105230000.0,,71748000.0,23842000.0,,599160000.0,6877800.0,3479000000.0,37935000.0,42397000000.0,8037700.0,143990000.0,119560000.0,516040000.0,62578000.0,267020000.0,100640000.0,,54243000.0,1169800000.0,,435010000.0,156280000.0,549790000.0,32705000.0,51633000.0,,1352400000.0,1526700000.0,4853100000.0,61582000.0,354990000.0,1699100000.0,1156500000.0,44309000.0,2216200000.0,92837000.0,983020000.0,2266800000.0,176340000.0,,313480000.0,15967000000.0,128230000.0,25706000.0,103290000000.0,948890000.0,554960000.0,1626600000.0,283590000.0,26645000.0,25338000.0,462160000.0,273240000.0,1480000000.0,664960000.0,781540000.0,23490000.0,,53830000.0,65577000.0,80455000.0,162560000.0,97655000.0,104960000.0,507360000.0,121700000.0,1116800000.0,49590000.0,,546130000.0,93225000.0,86827000.0,,12408000.0,611940000.0,37012000.0,30803000000.0,,530090000.0,65414000.0,,467730000.0,521550000.0,92944000.0,38427000.0,520620000.0,1008500000.0,104190000.0,,101260000.0,212840000.0,29694000.0,52581000.0,97713000.0,282840000.0,179040000.0,495650000.0,,359740000.0,570490000.0,301760000.0,3164500000.0,748840000.0,185940000.0,1937300000.0,101010000.0,56744000.0,75991000.0,1384700000.0,13244000000.0,13171000.0,3381700000.0,278260000.0,170400000.0,243010000.0,77605000.0,,11287000.0,855450000.0,117570000.0,,600020000.0,63279000.0,,211540000.0,2394800000.0,114990000.0,630570000.0,289960000.0,209520000.0,115240000.0,28610000.0,18353000.0,794340000.0,6689500000.0,1297900000.0,263830000.0,30534000.0,86873000.0,18851000.0,306580000.0,88299000.0,819850000.0,867670000.0,76409000.0,10751000.0,1452000000.0,3109100000.0,306800000.0,242540000.0, +2019_12_19_19_48_Q-Exactive-HF-X-Orbitrap_6070,87856000.0,277430000.0,31772000.0,122270000.0,3820000000.0,,138890000.0,352970000.0,102380000.0,81775000.0,,891420000.0,178870000.0,,33813000.0,257470000.0,,115700000.0,9545100000.0,93645000.0,113490000.0,66898000.0,25799000000.0,1606900000.0,1322200000.0,101360000.0,29349000.0,73541000.0,333110000.0,92340000.0,2696300000.0,1128400000.0,3031100000.0,2850700000.0,6717200000.0,46996000.0,530430000.0,,970470000.0,11414000000.0,300800000.0,69004000.0,6116000000.0,,,105720000.0,,2091900000.0,7805400000.0,6541300000.0,1276000000.0,315520000.0,,1089600000.0,610000000.0,67607000.0,444670000.0,66830000.0,1981600000.0,304580000.0,320570000.0,10190000000.0,70964000.0,28319000.0,,336240000.0,532870000.0,271060000.0,835560000.0,40160000.0,158380000.0,92813000.0,468970000.0,4130400000.0,88243000.0,119870000.0,1858900000.0,44979000.0,,31977000.0,237900000.0,11794000.0,2636200000.0,37577000.0,52897000000.0,13648000.0,49774000.0,142710000.0,267890000.0,44183000.0,190210000.0,15236000.0,,32433000.0,1189000000.0,,276470000.0,45420000.0,356930000.0,72967000.0,64857000.0,,1269400000.0,1622500000.0,3764900000.0,27759000.0,173140000.0,997060000.0,885060000.0,60026000.0,1329800000.0,141780000.0,679540000.0,1778100000.0,52447000.0,,119970000.0,11732000000.0,,15474000.0,107710000000.0,12020000.0,334390000.0,1116400000.0,470340000.0,,58392000.0,437800000.0,411380000.0,1296200000.0,383820000.0,607790000.0,54000000.0,155950000.0,26097000.0,74560000.0,108470000.0,91499000.0,57806000.0,,309070000.0,62863000.0,1295600000.0,90030000.0,,304390000.0,18895000.0,137020000.0,,118060000.0,368670000.0,27985000.0,23137000000.0,44410000.0,562050000.0,150190000.0,,364590000.0,462060000.0,,178490000.0,416460000.0,690440000.0,23534000.0,26543000.0,100630000.0,209110000.0,,12492000.0,120750000.0,147910000.0,228890000.0,479290000.0,,307210000.0,587010000.0,108790000.0,2529700000.0,541460000.0,188130000.0,1669800000.0,85403000.0,23174000.0,29553000.0,1068000000.0,10915000000.0,,3825800000.0,166710000.0,193160000.0,217070000.0,75108000.0,,25740000.0,373750000.0,150180000.0,,479030000.0,24812000.0,,140770000.0,1998600000.0,80960000.0,373600000.0,55254000.0,205010000.0,140390000.0,85323000.0,,549570000.0,4114500000.0,626300000.0,113500000.0,30118000.0,75605000.0,13033000.0,222470000.0,47210000.0,836560000.0,856220000.0,,,852920000.0,2697200000.0,81395000.0,190730000.0, +2019_12_20_14_15_Q-Exactive-HF-X-Orbitrap_6070,308010000.0,245000000.0,15610000.0,164430000.0,5294600000.0,,210960000.0,432630000.0,145180000.0,108340000.0,,653910000.0,221190000.0,12817000.0,21449000.0,293500000.0,,87933000.0,13855000000.0,221820000.0,387800000.0,132850000.0,37574000000.0,2514900000.0,2322800000.0,85675000.0,,127240000.0,232490000.0,179190000.0,3635900000.0,1388800000.0,5293900000.0,4344700000.0,11187000000.0,156830000.0,745320000.0,,2512200000.0,16128000000.0,424660000.0,35391000.0,477720000.0,,,139940000.0,,2513900000.0,9961300000.0,11271000000.0,2236400000.0,323430000.0,,1557700000.0,1836000000.0,98440000.0,764800000.0,199820000.0,4517400000.0,723540000.0,519780000.0,14699000000.0,74927000.0,44352000.0,,864900000.0,593280000.0,441520000.0,1389400000.0,62692000.0,155560000.0,127910000.0,694430000.0,5682500000.0,104660000.0,292280000.0,,272980000.0,9448400.0,99146000.0,357070000.0,24125000.0,2293900000.0,49334000.0,65561000000.0,42065000.0,125000000.0,161270000.0,530530000.0,72854000.0,325420000.0,124150000.0,,42345000.0,1522400000.0,,403760000.0,140120000.0,565530000.0,122470000.0,43922000.0,,1665500000.0,2289000000.0,4575400000.0,41283000.0,426040000.0,1335400000.0,1218700000.0,98472000.0,2125300000.0,191650000.0,912750000.0,2656700000.0,121510000.0,,310000000.0,18557000000.0,84590000.0,46103000.0,130830000000.0,20963000.0,3979900000.0,1689600000.0,262760000.0,,12794000.0,629270000.0,714250000.0,2103900000.0,1044000000.0,880100000.0,117840000.0,192780000.0,84163000.0,67663000.0,199160000.0,91380000.0,64543000.0,61045000.0,693320000.0,181440000.0,1789600000.0,149440000.0,,767380000.0,62475000.0,202130000.0,,251260000.0,720520000.0,37117000.0,31773000000.0,73355000.0,939300000.0,191950000.0,,742470000.0,866130000.0,,172140000.0,915220000.0,1019400000.0,,21397000.0,117480000.0,405740000.0,39130000.0,52366000.0,254740000.0,261610000.0,346410000.0,737640000.0,237690000.0,573970000.0,930310000.0,290620000.0,4113600000.0,868470000.0,214090000.0,5593600000.0,116680000.0,58903000.0,50428000.0,2439200000.0,15545000000.0,9012900.0,5484400000.0,92837000.0,299050000.0,290020000.0,138500000.0,,31988000.0,1378200000.0,355070000.0,120910000.0,815740000.0,42582000.0,,237960000.0,3345300000.0,143640000.0,581560000.0,108350000.0,292380000.0,263250000.0,170920000.0,,790230000.0,7968300000.0,1614800000.0,287490000.0,47213000.0,111900000.0,81471000.0,466860000.0,121200000.0,1112200000.0,1338400000.0,,,1655300000.0,4295100000.0,204120000.0,331920000.0,1216600000.0 +2019_12_27_12_29_Q-Exactive-HF-X-Orbitrap_6070,253490000.0,215110000.0,70180000.0,131990000.0,3691000000.0,,132810000.0,150750000.0,98495000.0,43371000.0,,,73315000.0,28792000.0,,154770000.0,,119890000.0,8027700000.0,228350000.0,1558700000.0,53163000.0,21600000000.0,1440800000.0,1144200000.0,51114000.0,25102000.0,72448000.0,171730000.0,85617000.0,2439800000.0,1098600000.0,2946800000.0,2531600000.0,5422100000.0,32904000.0,416330000.0,,1237500000.0,10307000000.0,282410000.0,70963000.0,281740000.0,,,79585000.0,,1845000000.0,6934100000.0,6469800000.0,1311600000.0,249130000.0,,1052700000.0,528870000.0,33525000.0,477380000.0,85851000.0,1998800000.0,227590000.0,312700000.0,8589500000.0,50401000.0,46226000.0,,186100000.0,624750000.0,236630000.0,620010000.0,53278000.0,80966000.0,52733000.0,121100000.0,3135600000.0,79165000.0,173790000.0,2330800000.0,13597000.0,,42346000.0,238870000.0,12666000.0,1979400000.0,16500000.0,41173000000.0,20192000.0,46626000.0,80601000.0,327870000.0,81483000.0,166080000.0,29444000.0,,46459000.0,1127200000.0,,409560000.0,18579000.0,234140000.0,108540000.0,73933000.0,,987970000.0,1280000000.0,2911900000.0,33017000.0,249260000.0,831940000.0,932620000.0,48150000.0,1608200000.0,130050000.0,445080000.0,1784200000.0,,,149180000.0,9598700000.0,,24077000.0,88307000000.0,721900000.0,333140000.0,795100000.0,362270000.0,,51889000.0,393980000.0,388040000.0,967410000.0,463980000.0,638860000.0,31499000.0,87729000.0,24328000.0,50597000.0,138630000.0,38789000.0,48149000.0,,218410000.0,66245000.0,797740000.0,116550000.0,,240200000.0,32631000.0,90780000.0,,128010000.0,508440000.0,,23665000000.0,29470000.0,403400000.0,95995000.0,,483590000.0,418460000.0,13698000.0,143880000.0,244950000.0,666790000.0,18584000.0,,106020000.0,139380000.0,,41991000.0,111750000.0,164610000.0,314670000.0,405020000.0,39900000.0,150190000.0,388860000.0,152520000.0,2065500000.0,567070000.0,153530000.0,1401100000.0,86436000.0,,22542000.0,1143800000.0,8187800000.0,27313000.0,3296900000.0,100960000.0,150860000.0,100090000.0,68547000.0,,25243000.0,675240000.0,,14287000.0,432270000.0,61763000.0,,203640000.0,1953900000.0,80158000.0,474240000.0,128520000.0,106500000.0,144620000.0,47380000.0,17526000.0,411610000.0,4234000000.0,810160000.0,,29946000.0,38582000.0,28573000.0,215780000.0,39806000.0,756840000.0,500870000.0,,,691770000.0,2488100000.0,,144700000.0,886350000.0 +2019_12_29_15_06_Q-Exactive-HF-X-Orbitrap_6070,472860000.0,,88868000.0,56674000.0,9081200000.0,20411000.0,401790000.0,273330000.0,224910000.0,392740000.0,382940000.0,,152230000.0,,47647000.0,369750000.0,,196330000.0,11000000000.0,180410000.0,439590000.0,20241000.0,60643000000.0,223720000.0,1100600000.0,65662000.0,110070000.0,152340000.0,198830000.0,57398000.0,4147800000.0,1477300000.0,8346700000.0,2553700000.0,14428000000.0,52972000.0,2882300000.0,,3225200000.0,12124000000.0,454370000.0,96204000.0,,,20811000.0,101380000.0,328700000.0,5466600000.0,12999000000.0,15237000000.0,4563600000.0,639760000.0,159830000.0,7987900000.0,1338900000.0,,491210000.0,169580000.0,3742200000.0,1114700000.0,265330000.0,9551500000.0,,76252000.0,27482000.0,888960000.0,862310000.0,3243400000.0,2004800000.0,52984000.0,58978000.0,69839000.0,357020000.0,8898100000.0,173770000.0,643610000.0,,207620000.0,,414430000.0,537970000.0,60879000.0,2374300000.0,36388000.0,132810000000.0,46880000.0,155960000.0,378310000.0,244090000.0,29129000.0,207910000.0,33560000.0,210420000.0,22356000.0,7210000000.0,2539400000.0,709220000.0,7962400.0,814590000.0,,37102000.0,702570000.0,2585100000.0,1761500000.0,5910800000.0,,336430000.0,773070000.0,2126700000.0,104990000.0,1842400000.0,292340000.0,1430200000.0,2038600000.0,276100000.0,174190000.0,,28432000000.0,206370000.0,,144070000000.0,24103000.0,4082200000.0,2544800000.0,851980000.0,22715000.0,103960000.0,892770000.0,1805300000.0,2127000000.0,521610000.0,557860000.0,109470000.0,99954000.0,341590000.0,339030000.0,61101000.0,,55908000.0,109190000.0,424300000.0,406980000.0,4294200000.0,115920000.0,161870000.0,253800000.0,17528000.0,214250000.0,42328000.0,112150000.0,881180000.0,21874000.0,94428000000.0,136840000.0,1091500000.0,290100000.0,49245000.0,1130000000.0,814740000.0,31373000.0,22890000.0,1473700000.0,505040000.0,56561000.0,23775000.0,286380000.0,327950000.0,116890000.0,,63135000.0,3112900000.0,274140000.0,471790000.0,228720000.0,548240000.0,194560000.0,,1913700000.0,410950000.0,82016000.0,3318900000.0,,142500000.0,191350000.0,715760000.0,20911000000.0,6558300.0,3203300000.0,919960000.0,203580000.0,,73898000.0,,,875790000.0,882000000.0,,1848200000.0,89853000.0,54084000.0,299320000.0,2170100000.0,132520000.0,116190000.0,195380000.0,382390000.0,72813000.0,27394000.0,74925000.0,1691900000.0,7366900000.0,3111100000.0,957840000.0,12603000.0,104600000.0,80960000.0,387360000.0,42019000.0,3051400000.0,1098500000.0,,,821780000.0,3693000000.0,49519000.0,104010000.0,23303000000.0 +2019_12_29_18_18_Q-Exactive-HF-X-Orbitrap_6070,368040000.0,,70719000.0,90370000.0,12378000000.0,,398220000.0,612040000.0,141220000.0,381760000.0,319140000.0,4745100000.0,165340000.0,213390000.0,64692000.0,484480000.0,17174000.0,429980000.0,12636000000.0,325590000.0,497100000.0,33576000.0,63093000000.0,250160000.0,1821900000.0,67057000.0,79366000.0,150020000.0,243210000.0,95039000.0,5013100000.0,1827500000.0,9741600000.0,3322400000.0,16694000000.0,64646000.0,3331700000.0,23039000.0,3924100000.0,13086000000.0,348620000.0,71738000.0,,,30203000.0,198830000.0,338460000.0,5903100000.0,17954000000.0,18310000000.0,5033300000.0,833280000.0,141810000.0,8927400000.0,1559500000.0,,586960000.0,300600000.0,3580200000.0,1318400000.0,325070000.0,8083700000.0,,215510000.0,5683800.0,1115300000.0,833530000.0,3285200000.0,2484000000.0,137920000.0,67991000.0,84879000.0,461790000.0,9912900000.0,200060000.0,634480000.0,,201970000.0,63685000.0,660920000.0,724830000.0,37824000.0,2302600000.0,33247000.0,132590000000.0,19321000.0,188570000.0,455100000.0,392420000.0,60868000.0,231020000.0,57163000.0,326850000.0,37175000.0,8189800000.0,1850400000.0,1099600000.0,10469000.0,908800000.0,75454000.0,105370000.0,1043700000.0,2665000000.0,1906800000.0,6689900000.0,,405800000.0,1909900000.0,2590100000.0,116920000.0,3811200000.0,321060000.0,1653800000.0,2084000000.0,514930000.0,133900000.0,253330000.0,31258000000.0,256230000.0,,172120000000.0,,4869300000.0,2926600000.0,1266000000.0,,,1100800000.0,2049000000.0,2063300000.0,576260000.0,829370000.0,248120000.0,375830000.0,422250000.0,394130000.0,47358000.0,,78204000.0,99926000.0,523200000.0,480940000.0,4980000000.0,100450000.0,239250000.0,225540000.0,95196000.0,315990000.0,48205000.0,170400000.0,1011600000.0,95450000.0,105810000000.0,55397000.0,1248600000.0,427640000.0,61015000.0,1322500000.0,937780000.0,149200000.0,74143000.0,1666900000.0,590080000.0,56385000.0,50218000.0,212260000.0,419500000.0,81938000.0,,401930000.0,3457600000.0,408520000.0,701320000.0,139140000.0,383670000.0,344900000.0,,2942900000.0,664220000.0,98604000.0,4044800000.0,59213000.0,127270000.0,205520000.0,1864400000.0,26338000000.0,8410600.0,3611400000.0,783640000.0,355640000.0,46679000.0,44065000.0,,,1082700000.0,1500900000.0,340320000.0,1748400000.0,36389000.0,107360000.0,492970000.0,2714000000.0,241830000.0,106170000.0,94225000.0,631860000.0,50487000.0,239810000.0,98216000.0,2550800000.0,8630200000.0,2771500000.0,830170000.0,,185770000.0,156950000.0,499860000.0,101350000.0,3346400000.0,1129100000.0,,,822710000.0,4171900000.0,102690000.0,101020000.0,24464000000.0 +2020_01_02_17_38_Q-Exactive-HF-X-Orbitrap_6070,48680000.0,,14975000.0,,4585500000.0,9570900.0,75969000.0,78343000.0,22333000.0,20516000.0,77264000.0,,30439000.0,106410000.0,,84952000.0,,92255000.0,4101900000.0,78195000.0,101960000.0,,29261000000.0,46745000.0,360890000.0,,,14673000.0,90490000.0,16842000.0,1196000000.0,291390000.0,2926600000.0,678680000.0,4998700000.0,,602840000.0,,1286800000.0,5034400000.0,14973000.0,,,38960000.0,,15791000.0,51025000.0,1688900000.0,6915300000.0,4566600000.0,1613700000.0,135240000.0,,1284700000.0,311270000.0,10285000.0,63125000.0,,1477600000.0,486370000.0,32143000.0,4953100000.0,,16030000.0,18553000.0,91300000.0,291530000.0,1088400000.0,352860000.0,,,,326630000.0,3324300000.0,,103130000.0,,34960000.0,,82841000.0,139580000.0,,626920000.0,21122000.0,82002000000.0,,16005000.0,40482000.0,71900000.0,,31977000.0,,41642000.0,,1530500000.0,,151120000.0,,159640000.0,,,162160000.0,587160000.0,542210000.0,2090000000.0,,114410000.0,688910000.0,940310000.0,51950000.0,1502700000.0,107090000.0,385540000.0,590250000.0,162110000.0,,,11103000000.0,33022000.0,,70711000000.0,27037000.0,446490000.0,680370000.0,358520000.0,,,109470000.0,480420000.0,522490000.0,140460000.0,146170000.0,34178000.0,47292000.0,45759000.0,49251000.0,,,,12596000.0,28697000.0,20473000.0,1834500000.0,29131000.0,52134000.0,35967000.0,31505000.0,37093000.0,,,258950000.0,,51801000000.0,,861030000.0,73304000.0,,153460000.0,154710000.0,,,227660000.0,136820000.0,9142800.0,,54311000.0,41034000.0,,,38375000.0,670890000.0,48297000.0,52017000.0,236350000.0,75416000.0,70761000.0,,727910000.0,72377000.0,,746660000.0,20562000.0,,20612000.0,426720000.0,8624500000.0,,665090000.0,165440000.0,52629000.0,,,,9994800.0,224800000.0,530140000.0,,772700000.0,,,10447000.0,551390000.0,,19866000.0,52730000.0,59534000.0,,,,767440000.0,2940000000.0,1166600000.0,275630000.0,,14108000.0,,112570000.0,,863910000.0,370870000.0,,,218370000.0,1555500000.0,,,3534200000.0 +2020_01_03_11_17_Q-Exactive-HF-X-Orbitrap_6070,66619000.0,,,55405000.0,7191900000.0,3630200.0,105950000.0,151530000.0,20786000.0,,108290000.0,405260000.0,81460000.0,284910000.0,,61982000.0,,137110000.0,6601300000.0,46287000.0,202690000.0,,60145000000.0,66675000.0,909910000.0,,85102000.0,32648000.0,44977000.0,29309000.0,3111000000.0,510530000.0,4716100000.0,1259700000.0,9344400000.0,,1036800000.0,,1058400000.0,12093000000.0,181400000.0,,,44248000.0,,48100000.0,104180000.0,1969700000.0,10389000000.0,8395500000.0,2615300000.0,157190000.0,,3685300000.0,565530000.0,20205000.0,88465000.0,,2395500000.0,636720000.0,125220000.0,6343700000.0,,67488000.0,,278270000.0,488890000.0,1887700000.0,1687600000.0,,,,247610000.0,5263500000.0,,201770000.0,,32899000.0,,144490000.0,439800000.0,,1460200000.0,,324880000000.0,,85224000.0,,130830000.0,18965000.0,49594000.0,15799000.0,152670000.0,,3376800000.0,,228170000.0,,518070000.0,,47635000.0,242250000.0,1244900000.0,1750300000.0,4285900000.0,,177060000.0,655750000.0,1654800000.0,57933000.0,2746100000.0,157500000.0,631010000.0,836450000.0,337410000.0,,,17127000000.0,150760000.0,,155710000000.0,,1909500000.0,1478100000.0,398580000.0,,,197390000.0,754170000.0,1078200000.0,91532000.0,291390000.0,35949000.0,,100810000.0,113630000.0,,,,85219000.0,49205000.0,70833000.0,3213000000.0,52367000.0,10690000.0,17006000.0,,,27718000.0,,753470000.0,,78753000000.0,,558290000.0,141010000.0,,158170000.0,285910000.0,,,656650000.0,87504000.0,,,121460000.0,18782000.0,37474000.0,,106420000.0,1233300000.0,20219000.0,254330000.0,,142550000.0,187650000.0,,724530000.0,179910000.0,,2796800000.0,,47193000.0,18199000.0,,14005000000.0,,624280000.0,187450000.0,75148000.0,,,,,413870000.0,240560000.0,267480000.0,834750000.0,22066000.0,,253880000.0,674710000.0,40607000.0,,,110010000.0,,,,1604300000.0,3197900000.0,1387600000.0,837690000.0,6691800.0,30183000.0,,90010000.0,,1103900000.0,413030000.0,6843600.0,14683000.0,591770000.0,2317500000.0,,86736000.0,8635000000.0 +2020_01_03_16_58_Q-Exactive-HF-X-Orbitrap_6070,254760000.0,,44656000.0,26138000.0,8382000000.0,106410000.0,262340000.0,417110000.0,97686000.0,269440000.0,292960000.0,,80436000.0,311970000.0,21273000.0,370330000.0,,207780000.0,10288000000.0,270650000.0,228140000.0,,69862000000.0,216660000.0,894800000.0,22145000.0,,141740000.0,240400000.0,,3134600000.0,1403500000.0,6732200000.0,2759100000.0,10531000000.0,,2110700000.0,,2524400000.0,9024600000.0,294750000.0,,,,,210070000.0,195110000.0,4120200000.0,14939000000.0,12269000000.0,4267300000.0,515420000.0,179860000.0,5029200000.0,839720000.0,27897000.0,367390000.0,162690000.0,2526000000.0,1018700000.0,98526000.0,10650000000.0,41109000.0,86332000.0,55923000.0,481160000.0,481000000.0,2225500000.0,1555900000.0,32479000.0,40941000.0,67732000.0,331220000.0,7193200000.0,79483000.0,381730000.0,,56720000.0,,261210000.0,421810000.0,,2132200000.0,124430000.0,119920000000.0,,138960000.0,181750000.0,199860000.0,,70917000.0,,95943000.0,,8939600000.0,,831560000.0,,455780000.0,50611000.0,58816000.0,477030000.0,2392500000.0,882510000.0,5112300000.0,,224790000.0,462530000.0,1891200000.0,76655000.0,761630000.0,197970000.0,1072700000.0,1504000000.0,280740000.0,83675000.0,31262000.0,22827000000.0,150060000.0,,140280000000.0,1007700000.0,1128400000.0,2114200000.0,666680000.0,23213000.0,,558890000.0,1531700000.0,1230000000.0,254290000.0,462420000.0,118720000.0,211220000.0,250400000.0,146550000.0,,,,119840000.0,437020000.0,238660000.0,4485500000.0,150120000.0,66426000.0,117350000.0,46444000.0,334330000.0,25020000.0,67987000.0,680820000.0,8638000.0,100040000000.0,,1133600000.0,206910000.0,12655000.0,1055400000.0,659910000.0,,24331000.0,847700000.0,457950000.0,,43759000.0,320930000.0,337690000.0,,,263010000.0,2492000000.0,191070000.0,453410000.0,343490000.0,147530000.0,224230000.0,,1827100000.0,341350000.0,89109000.0,2060600000.0,122410000.0,,36900000.0,538180000.0,26760000000.0,7231000.0,2600100000.0,326650000.0,259500000.0,,35578000.0,,,484700000.0,1146300000.0,63434000.0,2065300000.0,80102000.0,20502000.0,269500000.0,1428600000.0,147440000.0,84489000.0,183520000.0,386210000.0,42698000.0,9454700.0,17366000.0,1329200000.0,9278700000.0,2087800000.0,536130000.0,9815900.0,24307000.0,104220000.0,394740000.0,25981000.0,2472800000.0,663050000.0,930250000.0,26020000.0,398860000.0,2693000000.0,9996900.0,42293000.0,791370000.0 +2020_01_03_20_10_Q-Exactive-HF-X-Orbitrap_6070,153430000.0,,63874000.0,36957000.0,10509000000.0,12560000.0,334030000.0,334750000.0,106350000.0,280300000.0,285660000.0,,50914000.0,263700000.0,,362740000.0,,120650000.0,9847400000.0,215740000.0,300170000.0,,68788000000.0,119290000.0,986780000.0,20219000.0,70804000.0,132260000.0,250220000.0,60728000.0,3579700000.0,1487700000.0,6980800000.0,2840700000.0,9538900000.0,,2561800000.0,10191000.0,2447900000.0,9163200000.0,242790000.0,72693000.0,,,,168240000.0,165020000.0,3999100000.0,17140000000.0,11797000000.0,3430300000.0,596050000.0,101680000.0,8648800000.0,908750000.0,52008000.0,181970000.0,226330000.0,3245800000.0,1059000000.0,105710000.0,11522000000.0,21885000.0,120130000.0,25261000.0,609180000.0,509740000.0,2558500000.0,1701600000.0,42712000.0,19717000.0,88388000.0,532260000.0,6505200000.0,94528000.0,446460000.0,,35611000.0,44675000.0,389170000.0,408500000.0,52717000.0,1475700000.0,26941000.0,104010000000.0,,144640000.0,190310000.0,364830000.0,46834000.0,57983000.0,38070000.0,86116000.0,39546000.0,9259700000.0,,506130000.0,,922540000.0,48572000.0,10332000.0,619280000.0,2856500000.0,1092400000.0,4423400000.0,,356570000.0,1691400000.0,1689300000.0,98362000.0,1802300000.0,339010000.0,1012200000.0,1388400000.0,705590000.0,48572000.0,636470000.0,27415000000.0,191930000.0,,151850000000.0,64209000.0,1021300000.0,2117800000.0,823330000.0,,103600000.0,621350000.0,1513400000.0,1300600000.0,375030000.0,742820000.0,111580000.0,281680000.0,133370000.0,263010000.0,,,,37461000.0,393090000.0,276730000.0,5342100000.0,95791000.0,83096000.0,286020000.0,50980000.0,182720000.0,,66352000.0,807660000.0,,99426000000.0,104590000.0,1140600000.0,167930000.0,13797000.0,654200000.0,772290000.0,,,1330100000.0,245200000.0,,24980000.0,344830000.0,386280000.0,46833000.0,22278000.0,296350000.0,2918600000.0,281620000.0,400010000.0,299150000.0,214210000.0,188760000.0,23444000.0,2276700000.0,413130000.0,54915000.0,2493100000.0,54906000.0,39360000.0,86412000.0,1532100000.0,27627000000.0,,3131600000.0,309070000.0,295020000.0,,49096000.0,,,462890000.0,1072500000.0,,1558400000.0,66151000.0,35432000.0,283120000.0,960850000.0,223050000.0,38258000.0,170230000.0,361870000.0,72510000.0,19247000.0,17584000.0,1936700000.0,10190000000.0,1255700000.0,470360000.0,,66716000.0,117930000.0,470060000.0,33633000.0,1823100000.0,745110000.0,190910000.0,,519780000.0,3077900000.0,,53360000.0,20002000000.0 +2020_01_04_04_23_Q-Exactive-HF-X-Orbitrap_6070,145600000.0,,105420000.0,106410000.0,13867000000.0,23311000.0,474050000.0,512710000.0,147720000.0,357750000.0,378020000.0,1043800000.0,90349000.0,167280000.0,54206000.0,544170000.0,,326390000.0,9799000000.0,298990000.0,402410000.0,,82793000000.0,239500000.0,1690300000.0,41626000.0,81844000.0,129780000.0,256520000.0,123050000.0,3778000000.0,1901300000.0,8153000000.0,3128600000.0,14159000000.0,,2262400000.0,8696300.0,3204600000.0,12287000000.0,367180000.0,124080000.0,,,34502000.0,166030000.0,250500000.0,4662600000.0,20588000000.0,17400000000.0,4911500000.0,585100000.0,224100000.0,8609100000.0,1312300000.0,64725000.0,511060000.0,120920000.0,3158900000.0,1485800000.0,179110000.0,11670000000.0,43228000.0,226050000.0,87108000.0,788210000.0,1029500000.0,3379100000.0,1468800000.0,127160000.0,60028000.0,153500000.0,485820000.0,11555000000.0,56208000.0,605600000.0,,119520000.0,,557120000.0,489820000.0,,1551100000.0,83899000.0,187730000000.0,,109160000.0,219090000.0,597910000.0,36929000.0,136760000.0,61619000.0,132550000.0,40544000.0,10316000000.0,3785700000.0,868110000.0,,1142200000.0,64221000.0,223590000.0,754740000.0,2147600000.0,1721400000.0,5804500000.0,,345110000.0,1831100000.0,2048700000.0,120520000.0,1983500000.0,392240000.0,1325300000.0,1891100000.0,534580000.0,164330000.0,694390000.0,32217000000.0,160100000.0,,196470000000.0,1582100000.0,4707200000.0,2640400000.0,1099200000.0,15209000.0,27145000.0,907750000.0,2079800000.0,1688800000.0,409120000.0,654810000.0,142390000.0,666320000.0,206200000.0,436190000.0,,,,71085000.0,429620000.0,253240000.0,5750000000.0,152000000.0,173830000.0,333750000.0,25509000.0,231650000.0,31927000.0,86026000.0,1108700000.0,101710000.0,119480000000.0,88187000.0,1387700000.0,191460000.0,16528000.0,1249500000.0,1115400000.0,,49978000.0,2014200000.0,526150000.0,,60510000.0,303810000.0,361420000.0,81618000.0,,354690000.0,2573100000.0,315010000.0,393960000.0,601870000.0,498690000.0,220750000.0,,3743300000.0,429410000.0,125620000.0,3255300000.0,123810000.0,50678000.0,55904000.0,307520000.0,28218000000.0,,2937100000.0,733080000.0,353420000.0,,75426000.0,,,602090000.0,1745600000.0,,1778100000.0,131660000.0,35686000.0,258540000.0,2871100000.0,252470000.0,103810000.0,229070000.0,465700000.0,45600000.0,137590000.0,37452000.0,2186500000.0,8166100000.0,1988300000.0,1009500000.0,42173000.0,91082000.0,121190000.0,398000000.0,57716000.0,4053100000.0,897080000.0,,67364000.0,713920000.0,3581300000.0,41172000.0,142100000.0,28189000000.0 +2020_01_04_10_03_Q-Exactive-HF-X-Orbitrap_6070,,,,,4976000000.0,,46084000.0,,5327200.0,209770000.0,37379000.0,,,97159000.0,,17899000.0,,83625000.0,1289700000.0,40630000.0,,,19144000000.0,,221560000.0,,,18229000.0,23383000.0,,391980000.0,265950000.0,1147900000.0,312290000.0,1897600000.0,,342140000.0,,247830000.0,3212000000.0,47485000.0,,,,,18789000.0,16646000.0,1037900000.0,2515900000.0,2096300000.0,1376100000.0,14049000.0,12440000.0,310630000.0,212960000.0,,14572000.0,,1369900000.0,143400000.0,10110000.0,1632600000.0,,6107200.0,,109430000.0,142310000.0,423590000.0,205860000.0,,,,58847000.0,1590500000.0,,59202000.0,398880000.0,,,135560000.0,41299000.0,,412460000.0,,38844000000.0,,11109000.0,,53499000.0,,,,10139000.0,,2766700000.0,880530000.0,296160000.0,,220810000.0,,9811400.0,64461000.0,311490000.0,147640000.0,1564600000.0,,44822000.0,410370000.0,429110000.0,,904140000.0,44138000.0,49709000.0,304070000.0,34404000.0,,,5052100000.0,,,53286000000.0,,176870000.0,238800000.0,45552000.0,,,77246000.0,290510000.0,275180000.0,60167000.0,49587000.0,,94989000.0,,19499000.0,,,,,25086000.0,,1195700000.0,,5590500.0,12158000.0,,57402000.0,,,83061000.0,,34597000000.0,,93188000.0,24111000.0,,139100000.0,88199000.0,,,217330000.0,29312000.0,,15332000.0,40639000.0,63681000.0,,,22802000.0,228860000.0,10939000.0,106520000.0,75776000.0,8941200.0,,,347980000.0,57308000.0,,323140000.0,19946000.0,,,,7790600000.0,,646310000.0,13492000.0,128010000.0,,,,,86164000.0,170530000.0,,190970000.0,,,21338000.0,783020000.0,57621000.0,11147000.0,5409600.0,56297000.0,7786300.0,,,245700000.0,3174300000.0,239160000.0,48197000.0,,,24479000.0,39926000.0,,307440000.0,57807000.0,,7393900.0,27723000.0,476050000.0,,,15013000000.0 +2020_01_04_14_59_Q-Exactive-HF-X-Orbitrap_6070,,,,,3663800000.0,,16918000.0,300770000.0,19883000.0,12938000.0,57246000.0,,,71226000.0,,,,71042000.0,3383100000.0,42605000.0,50844000.0,,25184000000.0,221930000.0,196220000.0,,19361000.0,31180000.0,92077000.0,17276000.0,1130000000.0,502520000.0,2272600000.0,633850000.0,3854700000.0,,660370000.0,,959450000.0,3455000000.0,1439100000.0,,,,9384800.0,,31799000.0,1399200000.0,6907100000.0,3329100000.0,1478500000.0,51086000.0,95206000.0,1349300000.0,331580000.0,11746000.0,22194000.0,,1254200000.0,373220000.0,63323000.0,3478900000.0,,,,121640000.0,444510000.0,950070000.0,331920000.0,,,,54468000.0,3853800000.0,,120970000.0,,16066000.0,,118080000.0,125310000.0,,616780000.0,,69416000000.0,,83519000.0,47585000.0,42557000.0,,52972000.0,19262000.0,129410000.0,,2879700000.0,,33295000.0,,90154000.0,,,214030000.0,969940000.0,421000000.0,1578200000.0,,28558000.0,635210000.0,1055700000.0,17631000.0,1044500000.0,51421000.0,21149000.0,480180000.0,105450000.0,19644000.0,,11602000000.0,37479000.0,,40467000000.0,,1041900000.0,896910000.0,209520000.0,,,237540000.0,226010000.0,214210000.0,25707000.0,247470000.0,64867000.0,50600000.0,45592000.0,,,,,,42166000.0,123600000.0,2436400000.0,36240000.0,34445000.0,45712000.0,,76543000.0,,,323150000.0,,45988000000.0,,307740000.0,47858000.0,,71696000.0,88370000.0,,,450890000.0,43520000.0,,,80257000.0,33132000.0,,,70113000.0,678630000.0,50221000.0,90815000.0,,90162000.0,74023000.0,,784620000.0,51724000.0,9358300.0,583670000.0,,,57974000.0,,9926600000.0,,705740000.0,99178000.0,22718000.0,,4911500.0,,,,501660000.0,,309740000.0,,,28091000.0,976630000.0,28518000.0,,57246000.0,67461000.0,27843000.0,,,458530000.0,2741400000.0,610600000.0,182050000.0,,15085000.0,,42562000.0,,1013600000.0,282040000.0,18584000.0,,187420000.0,1322800000.0,,,5929800000.0 +2020_01_06_20_17_Q-Exactive-HF-X-Orbitrap_6070,475080000.0,,149480000.0,,18149000000.0,73972000.0,434650000.0,279420000.0,157280000.0,226300000.0,331780000.0,,302090000.0,186220000.0,,599680000.0,,551570000.0,19192000000.0,267420000.0,679270000.0,,82977000000.0,215860000.0,1771100000.0,,77334000.0,170750000.0,328070000.0,,6119700000.0,2063300000.0,13270000000.0,3370200000.0,17896000000.0,,3486700000.0,40669000.0,4483800000.0,19125000000.0,5232600000.0,155490000.0,7222900000.0,,31236000.0,221450000.0,352570000.0,8212000000.0,23814000000.0,22082000000.0,3241500000.0,832510000.0,131910000.0,9474800000.0,1719000000.0,64243000.0,652800000.0,304750000.0,3398800000.0,1042100000.0,360260000.0,11457000000.0,39847000.0,227830000.0,37628000.0,923120000.0,873900000.0,4011400000.0,2558500000.0,89278000.0,,136100000.0,686640000.0,14207000000.0,258300000.0,669660000.0,,145320000.0,,203640000.0,682510000.0,,3192700000.0,93883000.0,174180000000.0,,236030000.0,416540000.0,634150000.0,,281320000.0,64779000.0,456290000.0,,4837400000.0,2634800000.0,1269000000.0,18954000.0,1010200000.0,85731000.0,201180000.0,1093300000.0,3914900000.0,3390300000.0,8126500000.0,,541610000.0,1602100000.0,2212400000.0,247690000.0,2844900000.0,521970000.0,1650400000.0,2034800000.0,1037400000.0,120780000.0,297370000.0,38050000000.0,130980000.0,,216340000000.0,,2187600000.0,4339100000.0,1678000000.0,51235000.0,,957460000.0,2107600000.0,2893700000.0,829340000.0,917060000.0,271940000.0,770470000.0,647490000.0,542790000.0,66564000.0,,110210000.0,138110000.0,412800000.0,265770000.0,9202300000.0,182570000.0,236990000.0,544490000.0,44483000.0,227490000.0,69403000.0,196050000.0,1045600000.0,118730000.0,144230000000.0,93374000.0,2026800000.0,355330000.0,25836000.0,1202000000.0,867550000.0,57121000.0,40295000.0,2175900000.0,516170000.0,,51057000.0,294480000.0,256970000.0,109050000.0,,336450000.0,4334700000.0,282300000.0,320970000.0,490880000.0,628110000.0,472660000.0,,4278200000.0,825110000.0,125760000.0,4245500000.0,102030000.0,112860000.0,367010000.0,2287100000.0,21519000000.0,,3300300000.0,1179700000.0,529880000.0,54741000.0,146130000.0,,,831560000.0,2238300000.0,108270000.0,2581900000.0,138440000.0,225630000.0,315740000.0,2900500000.0,446180000.0,287850000.0,40125000.0,617470000.0,117680000.0,108560000.0,72430000.0,3075900000.0,12763000000.0,3815200000.0,1687600000.0,84927000.0,245550000.0,25662000.0,585670000.0,52316000.0,3545900000.0,1075300000.0,288320000.0,100050000.0,1319500000.0,6213100000.0,87840000.0,159980000.0,11295000000.0 +2020_01_08_16_43_Q-Exactive-HF-X-Orbitrap_6070,111550000.0,,22502000.0,,6993100000.0,,116990000.0,257260000.0,53797000.0,16190000.0,105750000.0,,,116980000.0,,199020000.0,,83357000.0,6340500000.0,71701000.0,138970000.0,,35358000000.0,315720000.0,492130000.0,,,65918000.0,76934000.0,37219000.0,1583100000.0,749750000.0,4205400000.0,906590000.0,5697500000.0,,1215500000.0,,1235000000.0,5789900000.0,17841000.0,,,905940000.0,,,87384000.0,2230000000.0,7915500000.0,5748600000.0,1461100000.0,197850000.0,182270000.0,2271200000.0,606550000.0,25016000.0,148570000.0,,1687100000.0,603670000.0,62981000.0,4428800000.0,,41507000.0,5691800.0,255320000.0,352060000.0,1456700000.0,552040000.0,,18593000.0,,285670000.0,5396900000.0,61145000.0,161690000.0,,60100000.0,,66979000.0,255980000.0,,911290000.0,4995800.0,94155000000.0,,106160000.0,60188000.0,102010000.0,,25013000.0,,90899000.0,,1895000000.0,1907100000.0,252330000.0,,443200000.0,,37614000.0,332200000.0,1930400000.0,745640000.0,3136400000.0,,188340000.0,848380000.0,1074900000.0,49772000.0,767240000.0,163010000.0,690760000.0,848760000.0,212330000.0,,37695000.0,17103000000.0,49374000.0,,83227000000.0,,601760000.0,1535800000.0,397240000.0,,,460850000.0,608860000.0,864570000.0,77318000.0,480240000.0,42799000.0,97464000.0,99908000.0,118750000.0,,,,38979000.0,312740000.0,150910000.0,3486100000.0,,75848000.0,92407000.0,21758000.0,,,,411480000.0,25799000.0,63174000000.0,,1205800000.0,87991000.0,,227890000.0,223770000.0,,,623490000.0,86823000.0,18140000.0,,179170000.0,68936000.0,,,130730000.0,1224600000.0,49802000.0,153510000.0,185280000.0,230120000.0,92411000.0,,1171000000.0,58633000.0,32613000.0,1120600000.0,49690000.0,36816000.0,75352000.0,382080000.0,15575000000.0,,875610000.0,130900000.0,59754000.0,,,,,,678340000.0,59467000.0,1157600000.0,,,93000000.0,962600000.0,42671000.0,,121880000.0,176510000.0,28434000.0,33546000.0,29740000.0,999700000.0,3924000000.0,1279600000.0,374040000.0,,67340000.0,16396000.0,155990000.0,25446000.0,1215300000.0,643820000.0,,,246530000.0,1919100000.0,,51133000.0,10364000000.0 +2020_01_09_11_07_Q-Exactive-HF-X-Orbitrap_6070,285920000.0,,52084000.0,46667000.0,7403500000.0,,300990000.0,,120520000.0,71859000.0,195240000.0,,51116000.0,82907000.0,20581000.0,180650000.0,,220070000.0,6948000000.0,82227000.0,179160000.0,,50500000000.0,70231000.0,909130000.0,17474000.0,41798000.0,123130000.0,212040000.0,13832000.0,2954100000.0,897470000.0,5225000000.0,1917300000.0,9147700000.0,,1272900000.0,,2357000000.0,8706100000.0,124660000.0,,,,,25887000.0,113620000.0,2792100000.0,9795400000.0,9600000000.0,2486800000.0,236190000.0,83692000.0,3006000000.0,693330000.0,62701000.0,254480000.0,62145000.0,2786000000.0,721980000.0,69540000.0,7228500000.0,,192610000.0,13949000.0,367560000.0,581000000.0,1631800000.0,1020600000.0,27698000.0,,,813770000.0,5461500000.0,,468900000.0,,50200000.0,,183850000.0,295750000.0,,1511600000.0,44090000.0,97039000000.0,,144640000.0,205620000.0,282760000.0,,115960000.0,,173770000.0,,2878800000.0,1098800000.0,495350000.0,,580130000.0,,123840000.0,545880000.0,2316500000.0,1082500000.0,2401900000.0,,177720000.0,1562300000.0,1019000000.0,53944000.0,2002300000.0,248620000.0,873050000.0,1491200000.0,125970000.0,92284000.0,,17387000000.0,56911000.0,,120850000000.0,1621000000.0,1087800000.0,1484800000.0,360640000.0,7895800.0,,710320000.0,1037900000.0,1093100000.0,299340000.0,280260000.0,149550000.0,315790000.0,105830000.0,164530000.0,,,,46241000.0,410920000.0,165390000.0,2949100000.0,78075000.0,95034000.0,103810000.0,18775000.0,173270000.0,,17708000.0,428540000.0,13866000.0,73106000000.0,,1157000000.0,104830000.0,,497770000.0,399010000.0,41700000.0,24358000.0,688990000.0,241860000.0,34818000.0,,195240000.0,85947000.0,25502000.0,,193640000.0,1813300000.0,65739000.0,304850000.0,231730000.0,105150000.0,66848000.0,8814100.0,1770400000.0,323560000.0,41779000.0,1934000000.0,15475000.0,28259000.0,60321000.0,1418000000.0,17565000000.0,5037500.0,1463700000.0,309790000.0,98692000.0,,79578000.0,,,537840000.0,686200000.0,105490000.0,1220900000.0,36996000.0,17815000.0,210360000.0,1493900000.0,123240000.0,37092000.0,,423580000.0,20752000.0,,21374000.0,1464100000.0,6083300000.0,2004600000.0,326010000.0,,70278000.0,,195430000.0,14076000.0,2017600000.0,535770000.0,72680000.0,10256000.0,487810000.0,2371400000.0,,33256000.0,13877000000.0 +2020_01_15_13_56_Q-Exactive-HF-X-Orbitrap_6070,126250000.0,325410000.0,18992000.0,26485000.0,2986200000.0,,124020000.0,158520000.0,31774000.0,15155000.0,,,54722000.0,69378000.0,,143560000.0,,63426000.0,5469100000.0,26647000.0,118710000.0,10136000.0,16610000000.0,458860000.0,634240000.0,45564000.0,7000300.0,40703000.0,141130000.0,13318000.0,1418100000.0,326010000.0,1304200000.0,874300000.0,3402600000.0,57710000.0,236880000.0,,693650000.0,6177300000.0,161840000.0,24873000.0,420810000.0,,,105200000.0,16109000.0,797280000.0,4822600000.0,3440800000.0,1073500000.0,223250000.0,,457120000.0,395130000.0,20563000.0,188930000.0,83549000.0,1044100000.0,284240000.0,133160000.0,5048900000.0,,,,37155000.0,339500000.0,109740000.0,449800000.0,32708000.0,47169000.0,54771000.0,43121000.0,2323100000.0,71775000.0,49580000.0,981010000.0,12679000.0,,,163300000.0,16596000.0,953420000.0,13611000.0,34805000000.0,9370100.0,27863000.0,21891000.0,188740000.0,,110250000.0,17727000.0,,11019000.0,1232900000.0,,146110000.0,13017000.0,256120000.0,17527000.0,,,495010000.0,764240000.0,2034500000.0,35834000.0,172420000.0,605240000.0,787460000.0,22425000.0,729190000.0,33904000.0,357240000.0,1241400000.0,35860000.0,,23734000.0,6310700000.0,,,41813000000.0,558610000.0,274910000.0,612320000.0,145870000.0,2284900.0,,199920000.0,115080000.0,493880000.0,245640000.0,35642000.0,,,,40094000.0,49304000.0,33999000.0,,,409520000.0,99682000.0,267540000.0,75471000.0,,128150000.0,48869000.0,40183000.0,,55531000.0,337220000.0,,14485000000.0,,343390000.0,10744000.0,,113190000.0,252380000.0,,27997000.0,121300000.0,309770000.0,3885800.0,15224000.0,44367000.0,58912000.0,3941000.0,8737800.0,93086000.0,149170000.0,242300000.0,229810000.0,198660000.0,89415000.0,231050000.0,68709000.0,1283300000.0,290000000.0,30300000.0,912230000.0,52465000.0,6748000.0,,707470000.0,7821900000.0,,2061100000.0,129450000.0,30753000.0,72618000.0,33446000.0,,,348950000.0,35378000.0,,342940000.0,42401000.0,,23772000.0,1165800000.0,33135000.0,211710000.0,142430000.0,71902000.0,45051000.0,30615000.0,2849500.0,285560000.0,3326200000.0,432460000.0,44389000.0,,87530000.0,9566500.0,109890000.0,,427000000.0,415820000.0,4083500.0,,520550000.0,1414100000.0,48176000.0,124350000.0, +2020_01_20_15_10_Q-Exactive-HF-X-Orbitrap_6070,927030000.0,,232580000.0,173290000.0,16965000000.0,171600000.0,376880000.0,,529230000.0,571620000.0,520220000.0,1133700000.0,295660000.0,343390000.0,135030000.0,920840000.0,33899000.0,563290000.0,20322000000.0,410750000.0,648830000.0,78373000.0,106720000000.0,479270000.0,2068500000.0,59237000.0,82027000.0,232250000.0,471810000.0,173250000.0,7230900000.0,2179800000.0,14644000000.0,4618200000.0,24592000000.0,,4137100000.0,24968000.0,5198300000.0,19655000000.0,497220000.0,179820000.0,15404000000.0,,63182000.0,515060000.0,393520000.0,8583500000.0,30174000000.0,28531000000.0,6570200000.0,1318200000.0,313150000.0,11485000000.0,2502400000.0,224300000.0,861960000.0,163930000.0,5938200000.0,1455800000.0,455250000.0,21867000000.0,94150000.0,273650000.0,88056000.0,1688700000.0,1471700000.0,5737700000.0,3445300000.0,135230000.0,214750000.0,123910000.0,952910000.0,14597000000.0,249190000.0,1070300000.0,,304360000.0,85572000.0,773810000.0,875740000.0,102500000.0,3500200000.0,197030000.0,233730000000.0,34471000.0,278140000.0,392090000.0,656090000.0,,274430000.0,93349000.0,469070000.0,66567000.0,10800000000.0,4634800000.0,1228300000.0,,1515500000.0,155390000.0,197850000.0,1681000000.0,4757200000.0,3116300000.0,8271300000.0,69546000.0,723250000.0,2576000000.0,2444700000.0,274890000.0,3614400000.0,760350000.0,3029700000.0,3917100000.0,582240000.0,401850000.0,328920000.0,45003000000.0,429950000.0,,292670000000.0,2067600000.0,8424000000.0,5434700000.0,1734900000.0,53423000.0,63689000.0,1644700000.0,2722300000.0,3973700000.0,1089700000.0,1402000000.0,335990000.0,631140000.0,624940000.0,551610000.0,,,53377000.0,198440000.0,1320600000.0,732590000.0,8297400000.0,445090000.0,292190000.0,309700000.0,9618300.0,313040000.0,106440000.0,264780000.0,1356900000.0,157640000.0,193120000000.0,200800000.0,2573900000.0,580920000.0,,1548900000.0,1110300000.0,122700000.0,59336000.0,2251200000.0,588620000.0,102360000.0,98081000.0,591330000.0,769290000.0,82066000.0,56557000.0,444990000.0,6475400000.0,374430000.0,764410000.0,106470000.0,1120600000.0,620660000.0,64107000.0,4276300000.0,1008300000.0,118380000.0,6397200000.0,93959000.0,240230000.0,346910000.0,1377900000.0,36008000000.0,,4936600000.0,845960000.0,498440000.0,80611000.0,256140000.0,,,1513700000.0,1167700000.0,275790000.0,3787000000.0,182910000.0,107310000.0,797780000.0,2759800000.0,588670000.0,195120000.0,149290000.0,1083300000.0,122770000.0,97393000.0,125180000.0,3286800000.0,13145000000.0,3263800000.0,1541800000.0,28392000.0,37736000.0,299780000.0,965540000.0,279490000.0,5334700000.0,1846800000.0,554100000.0,,1072800000.0,6073300000.0,92191000.0,234860000.0,29844000000.0 +2020_02_05_20_55_Q-Exactive-HF-X-Orbitrap_6070,570460000.0,,126720000.0,50917000.0,13848000000.0,71651000.0,444550000.0,507910000.0,256830000.0,385960000.0,1017800000.0,3151100000.0,304260000.0,194220000.0,37138000.0,581210000.0,,523700000.0,14674000000.0,421320000.0,682800000.0,,102460000000.0,449260000.0,2038700000.0,,122750000.0,235780000.0,447980000.0,103900000.0,5502600000.0,2053400000.0,17031000000.0,4622400000.0,21156000000.0,35717000.0,3303700000.0,27789000.0,4948700000.0,21724000000.0,457850000.0,159240000.0,,,49929000.0,437820000.0,336310000.0,6932900000.0,26289000000.0,22125000000.0,3537400000.0,788410000.0,107000000.0,11422000000.0,1635600000.0,156260000.0,565070000.0,106980000.0,5109400000.0,1045100000.0,299250000.0,14349000000.0,,103780000.0,83666000.0,1306100000.0,893640000.0,4058500000.0,2775600000.0,67303000.0,89354000.0,168510000.0,806360000.0,13979000000.0,287880000.0,791370000.0,,152060000.0,,588040000.0,544890000.0,44497000.0,2891800000.0,139680000.0,260060000000.0,,170240000.0,221200000.0,748570000.0,,214800000.0,72830000.0,381650000.0,,6407200000.0,4146500000.0,1396900000.0,,1040000000.0,182980000.0,268290000.0,1159100000.0,3401700000.0,1901600000.0,8565000000.0,,453320000.0,903250000.0,3132600000.0,194220000.0,4122200000.0,517490000.0,2271100000.0,2067100000.0,605470000.0,259170000.0,183010000.0,41688000000.0,114300000.0,,246430000000.0,,6703600000.0,4094900000.0,2587500000.0,15927000.0,79748000.0,1238500000.0,2399900000.0,3335200000.0,851400000.0,720030000.0,208490000.0,630220000.0,252250000.0,425760000.0,33571000.0,,,100370000.0,749950000.0,235810000.0,8582500000.0,81963000.0,126210000.0,454750000.0,77143000.0,213130000.0,51172000.0,120980000.0,1340400000.0,72599000.0,152980000000.0,,1873400000.0,724060000.0,37016000.0,1552800000.0,1232400000.0,,,2019200000.0,732140000.0,,42800000.0,421990000.0,364850000.0,26650000.0,19474000.0,628150000.0,4211700000.0,273650000.0,803090000.0,103560000.0,739690000.0,477220000.0,40767000.0,3318500000.0,853840000.0,184680000.0,4943800000.0,92200000.0,264450000.0,126080000.0,1575600000.0,37737000000.0,,3300400000.0,915790000.0,515690000.0,34247000.0,146670000.0,,,1070700000.0,1890800000.0,203720000.0,2361500000.0,138520000.0,171980000.0,625050000.0,3483900000.0,405230000.0,211140000.0,348250000.0,733490000.0,24081000.0,128790000.0,87798000.0,3182700000.0,11740000000.0,4547800000.0,1722200000.0,92394000.0,153980000.0,73590000.0,575090000.0,185470000.0,4262900000.0,1168400000.0,,43065000.0,1211900000.0,5530800000.0,,175770000.0,24984000000.0 +2020_02_10_15_41_Q-Exactive-HF-X-Orbitrap_6070,352960000.0,649450000.0,247620000.0,477200000.0,9029200000.0,19059000.0,,710020000.0,300300000.0,96348000.0,,,798010000.0,,143420000.0,380220000.0,53947000.0,363600000.0,23944000000.0,408430000.0,683620000.0,286440000.0,58597000000.0,4298600000.0,4458200000.0,395270000.0,237190000.0,319630000.0,866410000.0,250270000.0,8275800000.0,3104800000.0,10475000000.0,6973700000.0,19965000000.0,676900000.0,1726400000.0,21307000.0,6213900000.0,30935000000.0,824370000.0,324000000.0,1239700000.0,,33690000.0,579230000.0,145100000.0,4699000000.0,16942000000.0,19996000000.0,3405800000.0,1200700000.0,69128000.0,743930000.0,2388800000.0,254870000.0,1005600000.0,555770000.0,8393800000.0,692700000.0,1053500000.0,23861000000.0,56735000.0,217540000.0,,1524200000.0,1485700000.0,939080000.0,2006300000.0,341810000.0,495040000.0,370650000.0,416540000.0,8315000000.0,267140000.0,333300000.0,,236480000.0,28804000.0,92050000.0,1028600000.0,28947000.0,3291300000.0,72045000.0,75203000000.0,28683000.0,260460000.0,242300000.0,1342900000.0,178010000.0,763770000.0,494930000.0,,208220000.0,1926000000.0,,1501000000.0,419970000.0,1622000000.0,197770000.0,115390000.0,,3233600000.0,3874700000.0,9563600000.0,209060000.0,822400000.0,3074700000.0,3031100000.0,234440000.0,5421900000.0,314900000.0,1721500000.0,5595000000.0,231960000.0,39689000.0,345410000.0,37389000000.0,165070000.0,174730000.0,217570000000.0,2638500000.0,6809600000.0,4161900000.0,1065700000.0,26891000.0,169500000.0,1323600000.0,946850000.0,3287100000.0,1445700000.0,1138600000.0,59590000.0,,187670000.0,1143500000.0,275770000.0,212870000.0,148640000.0,177060000.0,1449900000.0,534830000.0,2334000000.0,107540000.0,44396000.0,1255000000.0,180090000.0,145900000.0,,286310000.0,1278900000.0,74743000.0,67331000000.0,222380000.0,1615900000.0,537620000.0,,1176800000.0,1814800000.0,213080000.0,492510000.0,1777800000.0,2457800000.0,,33186000.0,331920000.0,546360000.0,79473000.0,134610000.0,525660000.0,885860000.0,455470000.0,1406500000.0,,624670000.0,1499800000.0,651440000.0,7834600000.0,2357600000.0,710960000.0,4039400000.0,308930000.0,66930000.0,132410000.0,3602500000.0,31603000000.0,63735000.0,8844000000.0,576540000.0,631180000.0,767800000.0,487710000.0,,28667000.0,2066200000.0,350990000.0,200770000.0,1519900000.0,264830000.0,29046000.0,664540000.0,4864400000.0,183860000.0,1597700000.0,197270000.0,455580000.0,331310000.0,332430000.0,89448000.0,1502100000.0,11620000000.0,3062400000.0,808340000.0,119230000.0,445040000.0,117100000.0,567650000.0,178610000.0,2386400000.0,2748900000.0,259700000.0,9209100.0,3314500000.0,9997300000.0,439490000.0,795340000.0, +2020_02_11_10_35_Q-Exactive-HF-X-Orbitrap_6070,516840000.0,557710000.0,203690000.0,271620000.0,3676500000.0,,465820000.0,801040000.0,360180000.0,128670000.0,,,558900000.0,43671000.0,129030000.0,566240000.0,70866000.0,271700000.0,21521000000.0,272950000.0,590830000.0,284000000.0,53062000000.0,3888200000.0,3456500000.0,156790000.0,145860000.0,292620000.0,761330000.0,220590000.0,6726300000.0,2531200000.0,9408200000.0,6199600000.0,15792000000.0,335920000.0,1625900000.0,16670000.0,5234500000.0,24100000000.0,730440000.0,191340000.0,9003300000.0,,,659470000.0,103310000.0,2821500000.0,15400000000.0,17899000000.0,2704400000.0,1387000000.0,71552000.0,1521500000.0,1853400000.0,267660000.0,832200000.0,397920000.0,5695300000.0,579080000.0,798280000.0,14129000000.0,69706000.0,96766000.0,,1307700000.0,1431600000.0,453560000.0,1932800000.0,161960000.0,466310000.0,322810000.0,299220000.0,7326300000.0,183980000.0,255610000.0,,215490000.0,52194000.0,59103000.0,1142200000.0,29144000.0,4823500000.0,119680000.0,62867000000.0,59298000.0,286620000.0,394250000.0,935510000.0,187720000.0,655060000.0,339300000.0,,95759000.0,3902800000.0,,1109700000.0,496160000.0,1168000000.0,176390000.0,56223000.0,,2536100000.0,2888500000.0,8721700000.0,171860000.0,725160000.0,2533300000.0,2471000000.0,190640000.0,4462500000.0,186440000.0,1976400000.0,4575200000.0,216240000.0,17893000.0,509630000.0,30313000000.0,85640000.0,171600000.0,200950000000.0,2315600000.0,858660000.0,3642800000.0,1018700000.0,,55806000.0,1033200000.0,527690000.0,2724900000.0,1446900000.0,966750000.0,94102000.0,,154940000.0,160450000.0,133650000.0,157690000.0,90179000.0,184190000.0,1171600000.0,510650000.0,2647300000.0,263910000.0,19944000.0,1271500000.0,167810000.0,44671000.0,,352720000.0,1296800000.0,92686000.0,49694000000.0,178190000.0,1565100000.0,424050000.0,12340000.0,679830000.0,1273100000.0,314950000.0,372080000.0,1247800000.0,1832700000.0,55656000.0,38483000.0,302780000.0,539790000.0,67978000.0,132510000.0,453860000.0,617980000.0,399540000.0,1160200000.0,97326000.0,457000000.0,1258300000.0,461660000.0,6232500000.0,1766800000.0,683900000.0,3584100000.0,260500000.0,58751000.0,223170000.0,3013000000.0,22317000000.0,136450000.0,7270900000.0,622240000.0,399710000.0,711800000.0,387160000.0,,69277000.0,1757200000.0,275430000.0,185480000.0,1028700000.0,339820000.0,,577350000.0,5522700000.0,159720000.0,1196800000.0,259550000.0,452080000.0,326200000.0,260370000.0,87896000.0,1320000000.0,9818100000.0,2154700000.0,795330000.0,142300000.0,402160000.0,105090000.0,365600000.0,207510000.0,2498500000.0,1894700000.0,333290000.0,12236000.0,2651400000.0,7921100000.0,392990000.0,679550000.0, +2020_02_12_05_06_Q-Exactive-HF-X-Orbitrap_6070,450780000.0,682520000.0,227000000.0,500360000.0,7111400000.0,18583000.0,514830000.0,779080000.0,368470000.0,106720000.0,,,673600000.0,87162000.0,22328000.0,262680000.0,86396000.0,285650000.0,28105000000.0,373420000.0,865860000.0,313450000.0,57939000000.0,4393200000.0,4287800000.0,220080000.0,79998000.0,601130000.0,831210000.0,171750000.0,8675000000.0,3325400000.0,11154000000.0,7391900000.0,18513000000.0,353490000.0,1651600000.0,22612000.0,6443800000.0,32768000000.0,726910000.0,323620000.0,12312000000.0,,,677250000.0,108360000.0,3942700000.0,18973000000.0,21148000000.0,3682700000.0,1566600000.0,39166000.0,784850000.0,2283100000.0,174510000.0,1037300000.0,518630000.0,6042000000.0,685720000.0,969360000.0,21179000000.0,79769000.0,152440000.0,,649370000.0,1187300000.0,677220000.0,2155700000.0,477590000.0,289860000.0,448280000.0,606370000.0,9936000000.0,146550000.0,434650000.0,,223990000.0,,69943000.0,1157000000.0,42709000.0,3213700000.0,125050000.0,82437000000.0,73055000.0,257590000.0,243710000.0,1124300000.0,136210000.0,712580000.0,426590000.0,,130900000.0,3372200000.0,,1386800000.0,457470000.0,1374100000.0,260560000.0,19077000.0,,3019500000.0,3294600000.0,10903000000.0,158400000.0,621280000.0,3091000000.0,3120600000.0,142510000.0,4449700000.0,216340000.0,2175200000.0,6560000000.0,181190000.0,47592000.0,625750000.0,33012000000.0,123320000.0,188080000.0,223000000000.0,2215400000.0,7011100000.0,3682300000.0,1150300000.0,33063000.0,83182000.0,1359400000.0,792690000.0,3479600000.0,1852100000.0,2226800000.0,114840000.0,,147250000.0,213860000.0,174370000.0,193620000.0,146040000.0,198110000.0,1719100000.0,537710000.0,3314700000.0,406270000.0,29929000.0,1377000000.0,229410000.0,160880000.0,,416160000.0,992030000.0,223050000.0,58860000000.0,212320000.0,1555500000.0,483470000.0,26275000.0,1172000000.0,1791000000.0,257640000.0,440950000.0,2025800000.0,2649900000.0,116260000.0,,468510000.0,632170000.0,129680000.0,102410000.0,592070000.0,664490000.0,511090000.0,1435700000.0,354190000.0,599060000.0,1542700000.0,751790000.0,8030100000.0,2139700000.0,587830000.0,2449900000.0,298970000.0,68659000.0,175870000.0,2698500000.0,26027000000.0,68662000.0,8501900000.0,393850000.0,497380000.0,784660000.0,530000000.0,47301000000.0,,,379560000.0,198130000.0,1412600000.0,238260000.0,,588980000.0,5317200000.0,170810000.0,1650600000.0,276820000.0,627660000.0,459480000.0,299650000.0,71065000.0,1668800000.0,10396000000.0,2513200000.0,831670000.0,149350000.0,531130000.0,90726000.0,665130000.0,186200000.0,2837500000.0,2164500000.0,300370000.0,13873000.0,3463700000.0,9590200000.0,296930000.0,922710000.0, +2020_02_13_00_26_Q-Exactive-HF-X-Orbitrap_6070,1041500000.0,902880000.0,270090000.0,290030000.0,9503100000.0,53256000.0,393800000.0,771330000.0,475310000.0,204790000.0,,,498960000.0,123780000.0,99065000.0,330560000.0,97155000.0,403060000.0,30369000000.0,521050000.0,1160000000.0,292150000.0,64983000000.0,4299200000.0,4267100000.0,332930000.0,210960000.0,662420000.0,698720000.0,254110000.0,10249000000.0,3683600000.0,10855000000.0,8426500000.0,18170000000.0,250020000.0,1754600000.0,66713000.0,6108900000.0,35781000000.0,756200000.0,212800000.0,12472000000.0,,24667000.0,844900000.0,98563000.0,4555500000.0,17667000000.0,23057000000.0,5375300000.0,1513100000.0,37861000.0,796630000.0,2023800000.0,130330000.0,1016500000.0,474920000.0,7590100000.0,861850000.0,1123200000.0,20688000000.0,94792000.0,114610000.0,,599910000.0,1554100000.0,792460000.0,2457900000.0,289600000.0,352400000.0,334780000.0,1403400000.0,10714000000.0,159800000.0,475370000.0,,227240000.0,114680000.0,101560000.0,1000800000.0,,5990700000.0,24047000.0,91950000000.0,62232000.0,332890000.0,403220000.0,1306900000.0,143080000.0,825880000.0,423620000.0,,121580000.0,3076900000.0,,1223700000.0,486870000.0,1942500000.0,373200000.0,177280000.0,,3003000000.0,4010200000.0,12248000000.0,200850000.0,1187000000.0,2755500000.0,3045100000.0,227620000.0,4951100000.0,307500000.0,2333200000.0,6555700000.0,,47282000.0,638400000.0,30255000000.0,329560000.0,227080000.0,204600000000.0,2215600000.0,1235900000.0,3393000000.0,1210000000.0,70738000.0,73448000.0,913540000.0,1100700000.0,3403400000.0,1579300000.0,2058700000.0,194940000.0,463060000.0,170490000.0,1178600000.0,317780000.0,285110000.0,160610000.0,256190000.0,1712700000.0,513760000.0,3452200000.0,340730000.0,52873000.0,1493200000.0,70366000.0,28695000.0,,386340000.0,1276800000.0,205940000.0,62731000000.0,160570000.0,2220200000.0,473030000.0,21658000.0,1140500000.0,1762500000.0,54372000.0,516730000.0,1508100000.0,2498100000.0,106950000.0,64163000.0,258650000.0,799340000.0,45702000.0,42986000.0,328300000.0,744980000.0,819020000.0,1463300000.0,151610000.0,668940000.0,1470500000.0,682130000.0,7549700000.0,3005800000.0,586080000.0,4112100000.0,238110000.0,66589000.0,63438000.0,2420400000.0,26783000000.0,95652000.0,8692900000.0,730310000.0,580050000.0,506770000.0,509890000.0,44546000000.0,43818000.0,,535980000.0,401950000.0,1297600000.0,366840000.0,37699000.0,477020000.0,7275500000.0,90458000.0,1578000000.0,261850000.0,529160000.0,352780000.0,368040000.0,85839000.0,2068800000.0,9203800000.0,2740800000.0,792020000.0,87657000.0,442900000.0,176700000.0,827140000.0,119350000.0,2629900000.0,2563300000.0,,,3188700000.0,10287000000.0,461560000.0,913120000.0, +2020_02_13_03_11_Q-Exactive-HF-X-Orbitrap_6070,1468600000.0,934150000.0,295680000.0,259220000.0,11459000000.0,74892000.0,753790000.0,826130000.0,401990000.0,172630000.0,,,618570000.0,129930000.0,61961000.0,320560000.0,61405000.0,658080000.0,29370000000.0,447250000.0,1084900000.0,429430000.0,67090000000.0,4791800000.0,4082300000.0,482180000.0,158730000.0,651920000.0,763800000.0,209150000.0,9448000000.0,3899600000.0,11854000000.0,8734200000.0,18469000000.0,285660000.0,2483300000.0,48674000.0,7223400000.0,36982000000.0,896970000.0,204550000.0,,,24552000.0,898510000.0,74508000.0,4975700000.0,18757000000.0,25922000000.0,4247300000.0,1248600000.0,76238000.0,836580000.0,2603100000.0,206200000.0,437540000.0,855840000.0,8419700000.0,1132500000.0,949560000.0,21292000000.0,,121070000.0,,917590000.0,1599400000.0,856570000.0,2433400000.0,429680000.0,366900000.0,348230000.0,1504800000.0,12921000000.0,167910000.0,731840000.0,,236340000.0,79862000.0,152290000.0,1124300000.0,124330000.0,6196700000.0,111650000.0,90899000000.0,29077000.0,292230000.0,468070000.0,1668000000.0,150910000.0,885440000.0,405900000.0,,126140000.0,2933700000.0,,1478700000.0,439920000.0,1934300000.0,409180000.0,182170000.0,,3308100000.0,4522300000.0,11246000000.0,215810000.0,1095000000.0,3589800000.0,3874600000.0,177310000.0,6364700000.0,280000000.0,1716000000.0,6884700000.0,,,526740000.0,34348000000.0,283310000.0,121810000.0,195970000000.0,2208700000.0,1213500000.0,4698600000.0,1077000000.0,70748000.0,244750000.0,982280000.0,1146500000.0,4017800000.0,1482900000.0,2292400000.0,157390000.0,550620000.0,240340000.0,170340000.0,319630000.0,342180000.0,141490000.0,590630000.0,1736300000.0,543360000.0,3803700000.0,460030000.0,,1557300000.0,198840000.0,37496000.0,,521260000.0,1408800000.0,100170000.0,73145000000.0,109000000.0,2409500000.0,486980000.0,24537000.0,977500000.0,1776100000.0,79993000.0,525360000.0,1613200000.0,2752200000.0,128660000.0,,521560000.0,754030000.0,,62388000.0,664090000.0,896300000.0,822690000.0,1438000000.0,,643840000.0,1562700000.0,833840000.0,8073300000.0,2550300000.0,479830000.0,4638100000.0,239280000.0,49448000.0,202990000.0,2701800000.0,33141000000.0,231260000.0,11072000000.0,711680000.0,683090000.0,561210000.0,550700000.0,46757000000.0,123700000.0,1788300000.0,698250000.0,66786000.0,1375500000.0,368360000.0,37906000.0,503740000.0,6978300000.0,113800000.0,1875100000.0,229740000.0,526680000.0,456500000.0,442620000.0,207400000.0,2173800000.0,10852000000.0,2651400000.0,678710000.0,80471000.0,566790000.0,198940000.0,360870000.0,147430000.0,2662700000.0,2807500000.0,,,3072100000.0,9918100000.0,462810000.0,1415300000.0, +2020_02_17_13_55_Q-Exactive-HF-X-Orbitrap_6070,364000000.0,667470000.0,100410000.0,191080000.0,6007800000.0,,364240000.0,494930000.0,233010000.0,79527000.0,,,110580000.0,81507000.0,,233430000.0,31914000.0,290860000.0,15842000000.0,172270000.0,289220000.0,218580000.0,33250000000.0,1786600000.0,2353700000.0,146170000.0,,262680000.0,537510000.0,28223000.0,4584300000.0,1347800000.0,5178800000.0,3335000000.0,10161000000.0,172530000.0,962840000.0,22397000.0,3366100000.0,15105000000.0,253340000.0,149850000.0,,,,558710000.0,51598000.0,2280600000.0,12867000000.0,11168000000.0,1672100000.0,1020200000.0,,1489700000.0,1276700000.0,127710000.0,146600000.0,158420000.0,3510900000.0,1157900000.0,425430000.0,10574000000.0,40009000.0,139800000.0,,392940000.0,1351200000.0,469700000.0,1225700000.0,164140000.0,138430000.0,186910000.0,398200000.0,6215200000.0,142970000.0,302890000.0,2714900000.0,56659000.0,27604000.0,43746000.0,540960000.0,64316000.0,2472800000.0,91748000.0,66760000000.0,37910000.0,91322000.0,102520000.0,420240000.0,196430000.0,669440000.0,96380000.0,,110090000.0,2485500000.0,,509110000.0,110170000.0,629790000.0,55194000.0,29724000.0,,1872100000.0,2062100000.0,6008800000.0,152870000.0,357780000.0,2172700000.0,1381000000.0,37951000.0,2902500000.0,189990000.0,736580000.0,3246500000.0,100890000.0,43295000.0,283550000.0,18593000000.0,158460000.0,102360000.0,126380000000.0,107160000.0,495890000.0,2414900000.0,345890000.0,,48030000.0,834490000.0,674480000.0,1709400000.0,856490000.0,1067800000.0,110980000.0,,61864000.0,197050000.0,203440000.0,184140000.0,111770000.0,94233000.0,844550000.0,421820000.0,1720000000.0,242260000.0,69108000.0,700960000.0,139100000.0,98188000.0,,273750000.0,1095100000.0,,39680000000.0,121190000.0,337760000.0,290920000.0,,497610000.0,985180000.0,203360000.0,57585000.0,562370000.0,977360000.0,,,157520000.0,350840000.0,16972000.0,83788000.0,204700000.0,481090000.0,269090000.0,709710000.0,64597000.0,330200000.0,837290000.0,394390000.0,3911200000.0,1363500000.0,268270000.0,2276000000.0,148030000.0,70231000.0,98767000.0,1748700000.0,15677000000.0,25322000.0,4890400000.0,296670000.0,340790000.0,274110000.0,231210000.0,,31300000.0,1007700000.0,260580000.0,124000000.0,426230000.0,141880000.0,,262120000.0,3801400000.0,112530000.0,862170000.0,489020000.0,193870000.0,294470000.0,181550000.0,74049000.0,985040000.0,4490600000.0,1016600000.0,415910000.0,54194000.0,236280000.0,35435000.0,392250000.0,129880000.0,1770100000.0,3997200000.0,,,1573700000.0,5197500000.0,231530000.0,443610000.0, +2020_02_18_01_25_Q-Exactive-HF-X-Orbitrap_6070,395730000.0,470640000.0,55705000.0,90078000.0,6544800000.0,11219000.0,156630000.0,321380000.0,169570000.0,51004000.0,,,162600000.0,77042000.0,23294000.0,235520000.0,12607000.0,237440000.0,12932000000.0,50739000.0,209880000.0,107420000.0,33673000000.0,1477600000.0,1569000000.0,87977000.0,79464000.0,305830000.0,385210000.0,99234000.0,4629700000.0,1538700000.0,4505900000.0,3414400000.0,8510700000.0,184670000.0,984460000.0,10268000.0,2071400000.0,12122000000.0,2548700000.0,133470000.0,8536600000.0,,,325890000.0,70444000.0,2404400000.0,11815000000.0,10228000000.0,2270500000.0,746810000.0,36460000.0,672440000.0,1202500000.0,132080000.0,283280000.0,156850000.0,3388400000.0,657230000.0,325670000.0,7006200000.0,72887000.0,54039000.0,,318350000.0,1245400000.0,679300000.0,795010000.0,137360000.0,89905000.0,184770000.0,356600000.0,6363300000.0,97904000.0,223650000.0,3295200000.0,77535000.0,12068000.0,39103000.0,459520000.0,27280000.0,1846500000.0,30887000.0,68589000000.0,65196000.0,110370000.0,52926000.0,365650000.0,153800000.0,321290000.0,169500000.0,,57286000.0,2204700000.0,,612740000.0,45519000.0,717550000.0,56765000.0,60975000.0,,1264400000.0,2047900000.0,5909100000.0,117650000.0,318820000.0,1551900000.0,1883600000.0,57233000.0,2438000000.0,96642000.0,502470000.0,2310700000.0,86819000.0,17010000.0,418820000.0,19670000000.0,95041000.0,58943000.0,112570000000.0,24882000.0,215480000.0,1934500000.0,588730000.0,,89549000.0,639250000.0,615390000.0,1352700000.0,624750000.0,1120900000.0,77616000.0,,72322000.0,164470000.0,134060000.0,178880000.0,76217000.0,94352000.0,641300000.0,302920000.0,2255300000.0,117840000.0,66794000.0,404980000.0,45285000.0,206920000.0,,172940000.0,858190000.0,9997400.0,48650000000.0,73403000.0,491760000.0,172550000.0,,333740000.0,765240000.0,59824000.0,72339000.0,986290000.0,1062800000.0,108270000.0,,249430000.0,426000000.0,,68541000.0,266330000.0,428760000.0,190170000.0,475130000.0,,439820000.0,858910000.0,245200000.0,3620200000.0,1284300000.0,326560000.0,2072300000.0,104860000.0,38953000.0,54976000.0,863720000.0,13900000000.0,64008000.0,3811800000.0,203130000.0,243440000.0,173460000.0,216230000.0,60003000.0,14656000.0,729090000.0,310040000.0,81696000.0,420030000.0,165460000.0,,144810000.0,3812500000.0,59677000.0,470860000.0,459790000.0,248610000.0,195670000.0,79547000.0,31468000.0,565920000.0,6101700000.0,1353900000.0,197040000.0,77014000.0,284210000.0,,387490000.0,8028900.0,1310200000.0,1437500000.0,,5806400.0,920040000.0,4568400000.0,89585000.0,370030000.0, +2020_02_18_18_55_Q-Exactive-HF-X-Orbitrap_6070,150040000.0,427090000.0,75026000.0,469400000.0,4240600000.0,,366120000.0,377700000.0,220260000.0,74749000.0,,720530000.0,315230000.0,,40253000.0,298960000.0,7153800.0,156220000.0,14616000000.0,304320000.0,185980000.0,80885000.0,38552000000.0,1537300000.0,1662600000.0,124530000.0,80184000.0,190790000.0,415430000.0,67911000.0,2942800000.0,1162600000.0,5194400000.0,2912700000.0,11052000000.0,120700000.0,739190000.0,,2196500000.0,13661000000.0,318890000.0,172600000.0,,,,233640000.0,18736000.0,2734400000.0,9338300000.0,11160000000.0,1316400000.0,765210000.0,23843000.0,1248500000.0,1045900000.0,82020000.0,717780000.0,116850000.0,2886900000.0,647060000.0,530150000.0,8857900000.0,25490000.0,110630000.0,,448630000.0,541030000.0,369970000.0,1002400000.0,154920000.0,198750000.0,249540000.0,1202600000.0,6459600000.0,158980000.0,259870000.0,2819800000.0,73638000.0,,,541850000.0,53064000.0,2498100000.0,29103000.0,62649000000.0,9553500.0,257350000.0,214570000.0,593330000.0,,410570000.0,150050000.0,,51342000.0,824800000.0,,410820000.0,124290000.0,1019200000.0,54179000.0,66272000.0,,1446700000.0,2524800000.0,6546300000.0,85165000.0,431880000.0,1344000000.0,1412100000.0,104640000.0,1644000000.0,135380000.0,974140000.0,2200400000.0,94993000.0,15723000.0,255360000.0,22132000000.0,79592000.0,81574000.0,107500000000.0,1096000000.0,3278300000.0,1587900000.0,692330000.0,,81493000.0,833590000.0,321530000.0,2058600000.0,793540000.0,660610000.0,187970000.0,46109000.0,63345000.0,136250000.0,124900000.0,89041000.0,11968000.0,54465000.0,660960000.0,384020000.0,1416200000.0,97257000.0,19883000.0,659200000.0,79733000.0,93126000.0,,237100000.0,848210000.0,72448000.0,41106000000.0,15379000.0,1001000000.0,238630000.0,,609450000.0,957390000.0,188460000.0,68775000.0,552810000.0,1072900000.0,33698000.0,22122000.0,174110000.0,174430000.0,43706000.0,88369000.0,335110000.0,462050000.0,421720000.0,608100000.0,,307310000.0,855960000.0,341840000.0,3720500000.0,841350000.0,275070000.0,2261500000.0,49882000.0,17728000.0,73029000.0,979100000.0,13400000000.0,14945000.0,4407900000.0,308260000.0,273540000.0,238680000.0,108720000.0,14025000.0,14410000.0,,363080000.0,142310000.0,422690000.0,127330000.0,,186950000.0,2464400000.0,74272000.0,846620000.0,180170000.0,352820000.0,232870000.0,192650000.0,43267000.0,490260000.0,4487800000.0,1368700000.0,267270000.0,59815000.0,294840000.0,,478840000.0,77570000.0,1593600000.0,1582300000.0,129360000.0,5174200.0,1412600000.0,5227100000.0,268240000.0,275830000.0, +2020_02_28_12_27_Q-Exactive-HF-X-Orbitrap_6070,393350000.0,317600000.0,39159000.0,124950000.0,5263000000.0,,227750000.0,266560000.0,151900000.0,104580000.0,,,111260000.0,9816800.0,67781000.0,110580000.0,23119000.0,211120000.0,8519700000.0,270290000.0,232440000.0,26287000.0,27783000000.0,1669600000.0,1558200000.0,123210000.0,22127000.0,195990000.0,307230000.0,78724000.0,3682800000.0,1127100000.0,3911600000.0,2979800000.0,7046000000.0,89480000.0,359790000.0,16017000.0,1599100000.0,9651500000.0,453220000.0,80724000.0,8109500000.0,,16683000.0,189450000.0,11407000.0,1619600000.0,7665100000.0,8234600000.0,1830700000.0,418980000.0,27219000.0,301310000.0,899450000.0,58173000.0,511920000.0,146860000.0,2273000000.0,242900000.0,309890000.0,9590700000.0,44497000.0,55022000.0,,303080000.0,365780000.0,230290000.0,774060000.0,130870000.0,122500000.0,163120000.0,145160000.0,3949700000.0,93879000.0,92954000.0,,19614000.0,24742000.0,38087000.0,542680000.0,,1433600000.0,30443000.0,42203000000.0,7631500.0,130850000.0,142850000.0,317110000.0,51786000.0,413970000.0,95848000.0,,147940000.0,2503000000.0,,371300000.0,108900000.0,491650000.0,76338000.0,47006000.0,,1586200000.0,1726900000.0,3946400000.0,52652000.0,330010000.0,698110000.0,1047200000.0,1422400000.0,2021200000.0,150030000.0,587380000.0,2133400000.0,142180000.0,7590800.0,185630000.0,13723000000.0,190090000.0,38798000.0,75465000000.0,878380000.0,323780000.0,1407300000.0,345210000.0,12578000.0,49170000.0,428380000.0,340190000.0,1437400000.0,584830000.0,397200000.0,60769000.0,141300000.0,19808000.0,88389000.0,117660000.0,113080000.0,21889000.0,31115000.0,795940000.0,260570000.0,1761000000.0,94199000.0,,478610000.0,56123000.0,162920000.0,,244080000.0,429180000.0,77216000.0,27634000000.0,,701980000.0,131280000.0,6702700.0,358560000.0,583340000.0,13511000.0,245000000.0,415620000.0,792820000.0,50209000.0,16994000.0,156720000.0,393540000.0,33453000.0,29665000.0,65632000.0,277280000.0,255930000.0,479260000.0,69473000.0,291890000.0,574990000.0,206920000.0,2398800000.0,665340000.0,223020000.0,1510300000.0,120030000.0,12080000.0,61002000.0,1483600000.0,13058000000.0,26368000.0,3118400000.0,191030000.0,178520000.0,273420000.0,106890000.0,,23202000.0,876670000.0,168320000.0,,544680000.0,73211000.0,13353000.0,196040000.0,2538600000.0,100490000.0,569120000.0,207080000.0,195810000.0,175500000.0,145850000.0,37781000.0,482740000.0,4724500000.0,1123000000.0,183280000.0,49010000.0,169490000.0,34343000.0,178450000.0,100870000.0,1063600000.0,1074600000.0,109100000.0,15816000.0,1006200000.0,2807500000.0,152980000.0,277400000.0,1293500000.0 +2020_03_01_23_00_Q-Exactive-HF-X-Orbitrap_6070,254000000.0,160870000.0,12829000.0,82890000.0,3964800000.0,,206280000.0,229560000.0,92106000.0,44135000.0,,,123100000.0,7514200.0,24990000.0,118950000.0,14267000.0,81948000.0,7683400000.0,147320000.0,169560000.0,46054000.0,22858000000.0,844180000.0,1182200000.0,61914000.0,48975000.0,152420000.0,260900000.0,75693000.0,3373200000.0,1222900000.0,2751800000.0,2053800000.0,5044200000.0,93653000.0,491810000.0,,1321000000.0,7425200000.0,170770000.0,,524610000.0,,,124620000.0,10374000.0,1361100000.0,4897300000.0,6132600000.0,1183600000.0,262960000.0,11781000.0,205410000.0,639440000.0,42992000.0,320510000.0,98878000.0,1753800000.0,414050000.0,221830000.0,4943900000.0,24318000.0,24986000.0,,213210000.0,493850000.0,159520000.0,503510000.0,64754000.0,137040000.0,92111000.0,165380000.0,3434500000.0,77301000.0,172770000.0,,39385000.0,10261000.0,39551000.0,306050000.0,,1485900000.0,24440000.0,50712000000.0,30999000.0,136490000.0,119540000.0,625680000.0,41688000.0,239590000.0,71911000.0,,62514000.0,2036200000.0,,361880000.0,60070000.0,223480000.0,65660000.0,44999000.0,,984630000.0,1185400000.0,3048500000.0,39361000.0,165250000.0,919650000.0,878780000.0,48727000.0,1649900000.0,49000000.0,478490000.0,1377100000.0,73937000.0,,123430000.0,10024000000.0,34010000.0,19308000.0,77565000000.0,39409000.0,2051300000.0,1265000000.0,372070000.0,18643000.0,10179000.0,388180000.0,284290000.0,953270000.0,364730000.0,606640000.0,53958000.0,157780000.0,38352000.0,80149000.0,51216000.0,19894000.0,,218560000.0,555790000.0,135440000.0,1002000000.0,76008000.0,,246080000.0,48933000.0,52054000.0,,92027000.0,354270000.0,65043000.0,23956000000.0,47473000.0,494620000.0,86458000.0,4941400.0,313860000.0,428900000.0,17360000.0,40068000.0,328880000.0,562400000.0,76307000.0,12360000.0,181830000.0,246050000.0,,20766000.0,117480000.0,272700000.0,168760000.0,306340000.0,,241950000.0,633430000.0,54803000.0,1948800000.0,312750000.0,102020000.0,1874100000.0,45966000.0,13324000.0,28004000.0,913950000.0,9204500000.0,3733200.0,3533400000.0,158780000.0,115510000.0,129500000.0,60808000.0,,7347100.0,416590000.0,158350000.0,67285000.0,335420000.0,35030000.0,,155010000.0,1783200000.0,30638000.0,467270000.0,71001000.0,92886000.0,132960000.0,77110000.0,33625000.0,284570000.0,2839800000.0,804650000.0,176630000.0,25163000.0,197390000.0,31923000.0,150480000.0,52581000.0,775140000.0,1021000000.0,27330000.0,,778570000.0,1583400000.0,81597000.0,139570000.0, +2020_03_06_16_22_Q-Exactive-HF-X-Orbitrap_6070,69046000.0,,15836000.0,,3232500000.0,46193000.0,60117000.0,88369000.0,18852000.0,86020000.0,95904000.0,423210000.0,38740000.0,44822000.0,,76412000.0,,11856000.0,3738900000.0,86473000.0,95468000.0,,22287000000.0,,467820000.0,,,13451000.0,31013000.0,24185000.0,1097000000.0,386150000.0,2520600000.0,818580000.0,4232300000.0,,671680000.0,,933250000.0,5132300000.0,134820000.0,49721000.0,,,8183900.0,,10786000.0,1319200000.0,5170500000.0,4210200000.0,1214300000.0,64766000.0,49129000.0,1864700000.0,347960000.0,15477000.0,127190000.0,34830000.0,1338300000.0,334570000.0,49472000.0,3357200000.0,18927000.0,35395000.0,,320070000.0,178390000.0,1183900000.0,435560000.0,16887000.0,,,43573000.0,2360100000.0,14041000.0,267620000.0,,21454000.0,5162000.0,125210000.0,159630000.0,,520270000.0,31030000.0,57883000000.0,,86781000.0,82409000.0,108480000.0,,49560000.0,22549000.0,47727000.0,,2851500000.0,1016500000.0,249460000.0,,196880000.0,4333600.0,5465700.0,204310000.0,710450000.0,508600000.0,1537700000.0,,59439000.0,199760000.0,608630000.0,22815000.0,840260000.0,39604000.0,484940000.0,598980000.0,188270000.0,25990000.0,13176000.0,7439400000.0,37050000.0,,59611000000.0,22940000.0,1557200000.0,775700000.0,213920000.0,1913300.0,,251470000.0,513220000.0,591140000.0,91457000.0,201490000.0,37445000.0,75997000.0,73890000.0,108240000.0,,,,8822600.0,143590000.0,344190000.0,2525900000.0,14661000.0,45924000.0,46659000.0,3796900.0,64538000.0,,8922100.0,250290000.0,8295100.0,31645000000.0,,406070000.0,62480000.0,,282640000.0,165000000.0,,,343260000.0,56562000.0,38291000.0,10628000.0,96195000.0,84355000.0,20808000.0,3766900.0,31788000.0,723590000.0,88885000.0,138380000.0,105370000.0,116100000.0,67043000.0,,1186800000.0,98956000.0,8177600.0,912190000.0,29330000.0,30566000.0,62198000.0,810960000.0,8062500000.0,,796190000.0,223920000.0,84717000.0,,,,,213460000.0,320750000.0,,816210000.0,,6966000.0,90157000.0,557500000.0,58393000.0,29610000.0,44392000.0,125850000.0,14237000.0,,,498590000.0,2802000000.0,901440000.0,277990000.0,,38343000.0,4467700.0,123050000.0,7484000.0,778720000.0,271310000.0,33226000.0,,237130000.0,957130000.0,4076200.0,25235000.0,8977500000.0 +2020_03_07_18_15_Q-Exactive-HF-X-Orbitrap_6070,115810000.0,,37601000.0,33966000.0,7614200000.0,133580000.0,229630000.0,96411000.0,168290000.0,269040000.0,235370000.0,,114180000.0,105920000.0,16303000.0,238750000.0,13480000.0,200480000.0,7978400000.0,187840000.0,406640000.0,,41904000000.0,179570000.0,987720000.0,31285000.0,,60022000.0,233650000.0,54902000.0,2747000000.0,844420000.0,5762000000.0,1711900000.0,9128700000.0,16551000.0,1514400000.0,,2219800000.0,9325700000.0,197860000.0,75107000.0,,227800000.0,,465370000.0,81507000.0,2722900000.0,11415000000.0,10427000000.0,2417500000.0,290040000.0,196130000.0,5048000000.0,967850000.0,34290000.0,490770000.0,105630000.0,2362400000.0,994780000.0,120200000.0,8805600000.0,31962000.0,82662000.0,27635000.0,545850000.0,441560000.0,2433500000.0,1335900000.0,57724000.0,,,305980000.0,5901700000.0,95388000.0,431130000.0,,65834000.0,11785000.0,320350000.0,354530000.0,,1109700000.0,15665000.0,97411000000.0,18435000.0,138690000.0,287940000.0,292470000.0,38072000.0,128750000.0,35070000.0,143110000.0,52352000.0,3916900000.0,,502390000.0,,465580000.0,23338000.0,34234000.0,290700000.0,1293400000.0,1076500000.0,3494900000.0,,234050000.0,613030000.0,1114800000.0,52075000.0,1528200000.0,186100000.0,1106900000.0,1453700000.0,476780000.0,55155000.0,50490000.0,20582000000.0,119180000.0,,134230000000.0,,866760000.0,1710500000.0,666480000.0,4377800.0,,543990000.0,1013400000.0,1157000000.0,276070000.0,514130000.0,103350000.0,265690000.0,164770000.0,262280000.0,,,,58906000.0,577910000.0,235820000.0,4332100000.0,43364000.0,157200000.0,189970000.0,,168530000.0,51380000.0,54014000.0,561080000.0,21661000.0,69200000000.0,,1170100000.0,172160000.0,37380000.0,782370000.0,454160000.0,23754000.0,,1028500000.0,246580000.0,45213000.0,17879000.0,162990000.0,168880000.0,,16758000.0,223970000.0,2131900000.0,232130000.0,338650000.0,271110000.0,364710000.0,143450000.0,,1477300000.0,273400000.0,,2154000000.0,80150000.0,48207000.0,95575000.0,2789700000.0,21213000000.0,,1562300000.0,460550000.0,272520000.0,12376000.0,,,,690540000.0,580630000.0,,1469800000.0,,30506000.0,284940000.0,1329200000.0,112080000.0,92096000.0,10766000.0,398820000.0,74719000.0,23619000.0,36817000.0,1238400000.0,7376600000.0,1980900000.0,603210000.0,10358000.0,156570000.0,45056000.0,242510000.0,31654000.0,1706500000.0,447090000.0,,,535710000.0,2019400000.0,38743000.0,60502000.0,20664000000.0 +2020_03_11_11_25_Q-Exactive-HF-X-Orbitrap_6070,503520000.0,340780000.0,78635000.0,164410000.0,5800300000.0,,262960000.0,319910000.0,240030000.0,78560000.0,,,219780000.0,15993000.0,23526000.0,358490000.0,7539800.0,120030000.0,12309000000.0,132310000.0,150390000.0,124390000.0,29590000000.0,1517500000.0,1851500000.0,160390000.0,85294000.0,185050000.0,312870000.0,123620000.0,3858400000.0,1502200000.0,4907500000.0,3080800000.0,9977700000.0,86945000.0,1093400000.0,26155000.0,3124800000.0,11222000000.0,470020000.0,131140000.0,4505200000.0,,,336300000.0,73669000.0,2514000000.0,9318900000.0,10692000000.0,1791700000.0,589980000.0,31801000.0,926260000.0,1172000000.0,88879000.0,561700000.0,190570000.0,2525400000.0,612560000.0,438570000.0,8413400000.0,62068000.0,106990000.0,,309890000.0,554450000.0,321770000.0,967950000.0,150180000.0,186140000.0,238590000.0,193750000.0,5254700000.0,155820000.0,249350000.0,2317900000.0,76822000.0,,42342000.0,551190000.0,,1419800000.0,53094000.0,57352000000.0,83483000.0,217760000.0,220140000.0,366360000.0,,605630000.0,175970000.0,,77031000.0,3363600000.0,,582960000.0,133060000.0,696810000.0,92512000.0,37551000.0,,1542200000.0,2045800000.0,5760600000.0,102140000.0,650400000.0,1374800000.0,1532400000.0,187480000.0,1817400000.0,190680000.0,870080000.0,2728500000.0,75778000.0,7472000.0,289430000.0,17411000000.0,52203000.0,15837000.0,137060000000.0,,3284000000.0,1818200000.0,523460000.0,,78337000.0,175590000.0,519860000.0,1776200000.0,992800000.0,787110000.0,132340000.0,,51623000.0,132280000.0,175100000.0,118260000.0,35614000.0,46581000.0,1216200000.0,321880000.0,1228100000.0,56973000.0,,627170000.0,125400000.0,67717000.0,,291900000.0,778600000.0,75479000.0,34966000000.0,112530000.0,431510000.0,226080000.0,6819400.0,576620000.0,704940000.0,29165000.0,245310000.0,545780000.0,1076900000.0,91021000.0,,74646000.0,389740000.0,57763000.0,63945000.0,197040000.0,437060000.0,428080000.0,591120000.0,,327930000.0,760010000.0,296460000.0,3698600000.0,895170000.0,189610000.0,2298800000.0,185400000.0,25930000.0,85100000.0,1664200000.0,13867000000.0,53701000.0,3824000000.0,292150000.0,243510000.0,283120000.0,100000000.0,,,897880000.0,238910000.0,26906000.0,284050000.0,150960000.0,,114110000.0,2156100000.0,58049000.0,631110000.0,173810000.0,246550000.0,180830000.0,296880000.0,49123000.0,654430000.0,6075000000.0,909440000.0,346620000.0,68808000.0,288950000.0,79938000.0,355610000.0,34562000.0,1131400000.0,1434100000.0,104800000.0,,1474100000.0,4537700000.0,124290000.0,413620000.0, +2020_05_04_11_39_Q-Exactive-HF-X-Orbitrap_6070,329950000.0,,28663000.0,55023000.0,3013600000.0,,62015000.0,207210000.0,94613000.0,17355000.0,,,80365000.0,47265000.0,25970000.0,107070000.0,,70096000.0,5487300000.0,79429000.0,86162000.0,61651000.0,17890000000.0,719990000.0,823280000.0,47201000.0,21540000.0,67186000.0,156220000.0,40991000.0,2122100000.0,5010400000.0,2008900000.0,1518400000.0,3251300000.0,75918000.0,495580000.0,3215300.0,1108500000.0,5866600000.0,205250000.0,77331000.0,4981600000.0,,,136240000.0,22949000.0,785990000.0,4768200000.0,4093600000.0,1592600000.0,204730000.0,4683100.0,157860000.0,545780000.0,44577000.0,343030000.0,75899000.0,1532700000.0,104520000.0,192660000.0,5610600000.0,21709000.0,20871000.0,,144750000.0,368910000.0,131030000.0,362110000.0,34113000.0,80111000.0,45346000.0,118040000.0,2234900000.0,48321000.0,76314000.0,1151000000.0,24830000.0,6362800.0,23890000.0,183560000.0,2553200.0,1039800000.0,27094000.0,37138000000.0,27117000.0,63863000.0,94778000.0,136040000.0,18613000.0,212070000.0,59424000.0,,16623000.0,809210000.0,,169440000.0,49663000.0,255230000.0,43979000.0,23781000.0,,947200000.0,914350000.0,2157000000.0,63885000.0,203100000.0,777920000.0,773320000.0,25440000.0,828600000.0,80937000.0,269510000.0,1077000000.0,63695000.0,,48002000.0,8169900000.0,25506000.0,16706000.0,49587000000.0,12429000.0,1424400000.0,714770000.0,146200000.0,,5033700.0,291770000.0,249650000.0,596000000.0,258020000.0,325580000.0,6247200.0,75911000.0,,32579000.0,54650000.0,22535000.0,57064000.0,33852000.0,228200000.0,124980000.0,383290000.0,103220000.0,6506700.0,214720000.0,27370000.0,81791000.0,,80899000.0,309160000.0,29338000.0,16505000000.0,51635000.0,423620000.0,65038000.0,2156700.0,447160000.0,311410000.0,19279000.0,67223000.0,293950000.0,346140000.0,51441000.0,,91513000.0,148930000.0,34040000.0,27016000.0,106940000.0,204180000.0,252170000.0,326140000.0,,157410000.0,322500000.0,90932000.0,1563000000.0,371010000.0,58395000.0,503830000.0,55953000.0,3535400.0,37430000.0,681200000.0,7098800000.0,3711200.0,2752100000.0,224570000.0,67282000.0,179260000.0,56222000.0,,,346940000.0,61331000.0,,190640000.0,26394000.0,,51399000.0,1325700000.0,58461000.0,303890000.0,133150000.0,68649000.0,96703000.0,50121000.0,,262690000.0,2729000000.0,348270000.0,122490000.0,,98032000.0,,173750000.0,16415000.0,542430000.0,701340000.0,12276000.0,,419020000.0,1614800000.0,84082000.0,219380000.0, +2020_05_12_15_13_Q-Exactive-HF-X-Orbitrap_6070,225910000.0,140530000.0,50009000.0,44500000.0,3038500000.0,2950800.0,92824000.0,110190000.0,67126000.0,29835000.0,,288210000.0,57569000.0,8970200.0,6116800.0,90726000.0,,77820000.0,5504400000.0,40882000.0,81816000.0,51240000.0,16591000000.0,595730000.0,566750000.0,46741000.0,18343000.0,84145000.0,127430000.0,66070000.0,1686700000.0,428810000.0,2134700000.0,1625300000.0,3722100000.0,52478000.0,351300000.0,14574000.0,779870000.0,4748400000.0,131610000.0,58508000.0,147280000.0,,7880300.0,90333000.0,13465000.0,1164000000.0,4913300000.0,4326000000.0,1190800000.0,284020000.0,11352000.0,224750000.0,310800000.0,17473000.0,338340000.0,98436000.0,899080000.0,162650000.0,159390000.0,5350200000.0,11959000.0,24085000.0,,156940000.0,387630000.0,115170000.0,450070000.0,39547000.0,51489000.0,89361000.0,93472000.0,2450400000.0,58699000.0,148950000.0,1485400000.0,30117000.0,10882000.0,29272000.0,206740000.0,,742490000.0,25911000.0,33250000000.0,28549000.0,57735000.0,54417000.0,164820000.0,,177480000.0,52009000.0,,12620000.0,727470000.0,,176980000.0,49630000.0,334320000.0,50565000.0,8755700.0,,688220000.0,941260000.0,2110800000.0,40184000.0,123050000.0,702900000.0,645020000.0,11415000.0,1106700000.0,19020000.0,225690000.0,1146300000.0,63415000.0,7778500.0,75819000.0,8371300000.0,18088000.0,,53306000000.0,,225550000.0,851410000.0,430790000.0,,,317180000.0,98256000.0,637150000.0,270350000.0,124950000.0,8006200.0,87325000.0,13036000.0,67009000.0,77357000.0,31599000.0,81639000.0,21883000.0,205910000.0,159200000.0,544300000.0,105120000.0,1732100.0,213870000.0,16954000.0,79798000.0,,89147000.0,339330000.0,30427000.0,16954000000.0,,360820000.0,67991000.0,2681300.0,227840000.0,264270000.0,47204000.0,101340000.0,260140000.0,445530000.0,46541000.0,7886000.0,81636000.0,242450000.0,17909000.0,37712000.0,125790000.0,510100000.0,227640000.0,263910000.0,57074000.0,132840000.0,314740000.0,95930000.0,1387000000.0,308220000.0,66597000.0,865580000.0,63892000.0,4745700.0,21445000.0,791120000.0,7413600000.0,19096000.0,1569600000.0,170770000.0,56321000.0,89691000.0,45253000.0,,5491400.0,,97237000.0,3738700.0,154020000.0,26861000.0,,75658000.0,1203000000.0,55363000.0,219620000.0,64743000.0,110570000.0,85628000.0,45731000.0,15484000.0,192770000.0,2207300000.0,433510000.0,94699000.0,8715900.0,89704000.0,8257500.0,184200000.0,6837300.0,661030000.0,537620000.0,17079000.0,6615200.0,574630000.0,2033400000.0,98667000.0,214890000.0, +2020_05_12_18_10_Q-Exactive-HF-X-Orbitrap_6070,195040000.0,100680000.0,33609000.0,65033000.0,1710800000.0,4788300.0,84650000.0,65379000.0,82616000.0,28798000.0,,,66065000.0,,17074000.0,92943000.0,,75497000.0,4814500000.0,10796000.0,92451000.0,61057000.0,13574000000.0,348120000.0,669920000.0,40262000.0,28920000.0,41551000.0,124060000.0,38831000.0,1586300000.0,438550000.0,1634100000.0,1483700000.0,2967200000.0,31722000.0,254400000.0,8929700.0,953410000.0,3229800000.0,139470000.0,42210000.0,94993000.0,,6372800.0,91132000.0,,885040000.0,3681800000.0,3547800000.0,662800000.0,263420000.0,9532200.0,132150000.0,239070000.0,42753000.0,286700000.0,71963000.0,1241900000.0,117390000.0,101870000.0,3770800000.0,18175000.0,19005000.0,,131120000.0,349090000.0,87354000.0,364640000.0,21190000.0,78223000.0,51759000.0,85985000.0,2046400000.0,59213000.0,83249000.0,1218900000.0,14551000.0,9624300.0,10797000.0,221900000.0,,781530000.0,23969000.0,20978000000.0,9403700.0,41768000.0,39502000.0,149650000.0,,150590000.0,45054000.0,,19031000.0,979850000.0,,202640000.0,56262000.0,268050000.0,67313000.0,21282000.0,,541610000.0,652940000.0,1653500000.0,28910000.0,115960000.0,587700000.0,570120000.0,19644000.0,717670000.0,68806000.0,263360000.0,904410000.0,69530000.0,4118700.0,47894000.0,6054100000.0,19297000.0,20931000.0,33337000000.0,,909010000.0,695460000.0,142610000.0,7843000.0,16115000.0,258800000.0,192990000.0,569250000.0,253930000.0,308430000.0,16373000.0,44389000.0,,45649000.0,44767000.0,49013000.0,39409000.0,5228600.0,154190000.0,131240000.0,393180000.0,110540000.0,,191370000.0,3904600.0,27874000.0,,65198000.0,292070000.0,17844000.0,12751000000.0,27067000.0,276630000.0,57492000.0,,173180000.0,303060000.0,12139000.0,46000000.0,224260000.0,350390000.0,25468000.0,,71260000.0,89813000.0,4481100.0,14846000.0,110530000.0,192540000.0,84532000.0,225670000.0,,171720000.0,237040000.0,71682000.0,1166600000.0,281770000.0,29350000.0,713060000.0,44249000.0,4685600.0,17251000.0,633430000.0,5042200000.0,3992400.0,1552500000.0,141010000.0,24642000.0,91235000.0,17785000.0,,,274670000.0,34415000.0,3675900.0,111000000.0,26018000.0,2379600.0,63631000.0,1191200000.0,40795000.0,247310000.0,133920000.0,67046000.0,76604000.0,47639000.0,8272800.0,198080000.0,2021700000.0,280170000.0,132960000.0,,67011000.0,5903700.0,124310000.0,14797000.0,701700000.0,579430000.0,35896000.0,,531300000.0,1484200000.0,78766000.0,126800000.0, +2020_05_12_21_07_Q-Exactive-HF-X-Orbitrap_6070,195050000.0,93935000.0,15720000.0,45623000.0,2070400000.0,,62364000.0,155320000.0,75798000.0,23780000.0,,255580000.0,56046000.0,40843000.0,18417000.0,71326000.0,,60992000.0,4691100000.0,26713000.0,62375000.0,47514000.0,13667000000.0,747600000.0,655930000.0,35982000.0,19403000.0,38575000.0,125170000.0,43391000.0,1657500000.0,3336100000.0,1629200000.0,1337900000.0,3106200000.0,34949000.0,343950000.0,3456800.0,679230000.0,3949900000.0,65604000.0,17417000.0,139930000.0,,13759000.0,67509000.0,11537000.0,898030000.0,3927200000.0,3828600000.0,1132400000.0,380880000.0,10514000.0,307160000.0,351660000.0,46142000.0,281520000.0,76293000.0,1301500000.0,183640000.0,128160000.0,4319700000.0,10283000.0,27667000.0,,131390000.0,365400000.0,100470000.0,308130000.0,29526000.0,57168000.0,72476000.0,93122000.0,2023900000.0,38703000.0,95247000.0,1228000000.0,15514000.0,10958000.0,13305000.0,206090000.0,,565580000.0,8099200.0,27570000000.0,14943000.0,52888000.0,58015000.0,121470000.0,35055000.0,205660000.0,45720000.0,,11000000.0,493620000.0,,217560000.0,22309000.0,261250000.0,47535000.0,37214000.0,,505290000.0,693290000.0,1735300000.0,35711000.0,115670000.0,520770000.0,525510000.0,3709300.0,833670000.0,16199000.0,236740000.0,766380000.0,36943000.0,,86180000.0,6929800000.0,19456000.0,7803200.0,34653000000.0,16077000.0,180670000.0,744150000.0,367190000.0,,12004000.0,241590000.0,149730000.0,540870000.0,246530000.0,184190000.0,10207000.0,69015000.0,,32133000.0,54614000.0,56078000.0,65909000.0,18455000.0,194180000.0,101910000.0,405900000.0,88287000.0,7467600.0,188030000.0,47453000.0,54427000.0,,71358000.0,302340000.0,20927000.0,12275000000.0,34651000.0,302430000.0,51582000.0,,214710000.0,191990000.0,25397000.0,29032000.0,239270000.0,324410000.0,22800000.0,13112000.0,79938000.0,145120000.0,16631000.0,37320000.0,113260000.0,417440000.0,113720000.0,241520000.0,,165030000.0,291580000.0,50550000.0,1210800000.0,238400000.0,37056000.0,949950000.0,37465000.0,22522000.0,19995000.0,696800000.0,6114300000.0,,1464200000.0,110050000.0,37568000.0,146650000.0,45446000.0,,15248000.0,427410000.0,100790000.0,4487700.0,130120000.0,32243000.0,,94308000.0,1003800000.0,24293000.0,225010000.0,105290000.0,95269000.0,100060000.0,19581000.0,4540600.0,208890000.0,2331100000.0,317020000.0,97617000.0,4306200.0,85896000.0,,161460000.0,27725000.0,583130000.0,694700000.0,30359000.0,,533980000.0,1599600000.0,80729000.0,111520000.0, +2020_05_14_14_46_Q-Exactive-HF-X-Orbitrap_6070,210700000.0,129710000.0,31399000.0,56876000.0,3581200000.0,,113750000.0,173940000.0,64519000.0,16566000.0,,,112910000.0,6785600.0,5338100.0,120910000.0,,93429000.0,6212500000.0,394180000.0,99575000.0,32436000.0,20792000000.0,696610000.0,851240000.0,61788000.0,34254000.0,49806000.0,165450000.0,37323000.0,2413800000.0,776630000.0,2615500000.0,1742700000.0,4447800000.0,31150000.0,340410000.0,4142500.0,922060000.0,6382000000.0,149240000.0,38459000.0,,,,117150000.0,24105000.0,1045800000.0,4868600000.0,4971300000.0,1324700000.0,392830000.0,7914700.0,615800000.0,493230000.0,53611000.0,287000000.0,80308000.0,1733600000.0,436240000.0,184430000.0,6261100000.0,,50578000.0,,149350000.0,505510000.0,195070000.0,415020000.0,54757000.0,107510000.0,42001000.0,92204000.0,2683800000.0,35836000.0,92824000.0,,21921000.0,7544000.0,11072000.0,190750000.0,13653000.0,971290000.0,23087000.0,33146000000.0,15647000.0,66502000.0,70518000.0,267450000.0,28871000.0,159800000.0,59928000.0,,11093000.0,1436800000.0,,163550000.0,44346000.0,343350000.0,28975000.0,,,992990000.0,990740000.0,2281000000.0,33683000.0,154420000.0,983650000.0,920320000.0,24115000.0,1120900000.0,40288000.0,309710000.0,1230300000.0,,4332100.0,51113000.0,8203400000.0,29793000.0,29362000.0,54130000000.0,759010000.0,276620000.0,1126700000.0,178560000.0,,17980000.0,234550000.0,305280000.0,652760000.0,315400000.0,239530000.0,8935900.0,,8002000.0,310120000.0,68624000.0,20179000.0,18511000.0,20527000.0,510940000.0,151320000.0,875030000.0,37188000.0,,1348500000.0,18037000.0,54915000.0,,119180000.0,363380000.0,9183700.0,17859000000.0,6373400.0,313840000.0,75969000.0,,269320000.0,357140000.0,56222000.0,28570000.0,242220000.0,341750000.0,37140000.0,,87795000.0,145570000.0,4650800.0,22214000.0,117110000.0,192740000.0,141260000.0,220590000.0,,133080000.0,363310000.0,144220000.0,1197500000.0,614810000.0,40893000.0,1230800000.0,49934000.0,4874000.0,26885000.0,846420000.0,8368500000.0,30819000.0,3330300000.0,178810000.0,69777000.0,179950000.0,50699000.0,,,311360000.0,53993000.0,42907000.0,334680000.0,45184000.0,,85190000.0,2360500000.0,29655000.0,311310000.0,112050000.0,109580000.0,67163000.0,64012000.0,,305060000.0,3440600000.0,600650000.0,168580000.0,17529000.0,90426000.0,28164000.0,195890000.0,,664770000.0,491890000.0,26426000.0,,626520000.0,2028500000.0,67007000.0,202010000.0, +2020_05_14_17_28_Q-Exactive-HF-X-Orbitrap_6070,105420000.0,381990000.0,23271000.0,45897000.0,2954000000.0,,108000000.0,233760000.0,72823000.0,45952000.0,,,77657000.0,8168400.0,,165010000.0,,46029000.0,6250600000.0,18803000.0,128270000.0,53724000.0,18422000000.0,850300000.0,722260000.0,49479000.0,46287000.0,99612000.0,160620000.0,34327000.0,2585800000.0,741720000.0,2542300000.0,1761300000.0,4864300000.0,42316000.0,364980000.0,,1269100000.0,8725200000.0,53724000.0,49863000.0,,,,120200000.0,18375000.0,1160900000.0,5060400000.0,5090900000.0,954940000.0,388890000.0,10690000.0,615740000.0,423810000.0,46617000.0,283580000.0,105090000.0,1618600000.0,479940000.0,209990000.0,6034400000.0,,34702000.0,,169220000.0,407260000.0,140160000.0,321490000.0,29283000.0,72655000.0,327020000.0,121950000.0,2768000000.0,98360000.0,115760000.0,1476500000.0,,5643100.0,,133040000.0,14294000.0,1073900000.0,26383000.0,30848000000.0,12453000.0,66522000.0,112950000.0,189400000.0,10336000.0,161900000.0,76047000.0,,20189000.0,1607400000.0,,272780000.0,62576000.0,358490000.0,71108000.0,7507500.0,,891870000.0,1096900000.0,2477300000.0,41409000.0,123790000.0,811630000.0,764210000.0,50275000.0,691130000.0,47414000.0,324180000.0,1559100000.0,,,88885000.0,9544800000.0,23208000.0,15776000.0,58324000000.0,811460000.0,286170000.0,886510000.0,218210000.0,,6304900.0,257970000.0,169780000.0,658270000.0,403810000.0,257550000.0,,75668000.0,11894000.0,58524000.0,37267000.0,19718000.0,,14787000.0,619730000.0,131650000.0,702650000.0,42170000.0,,1230800000.0,37478000.0,51706000.0,,108540000.0,313320000.0,16712000.0,16692000000.0,22082000.0,250580000.0,76048000.0,,291960000.0,386190000.0,42965000.0,45640000.0,297920000.0,430470000.0,33828000.0,,77006000.0,126130000.0,35913000.0,72939000.0,110750000.0,212530000.0,247540000.0,230130000.0,,171750000.0,313920000.0,251310000.0,1537700000.0,529700000.0,81272000.0,1392700000.0,41692000.0,,34303000.0,919610000.0,8737500000.0,,2994000000.0,186770000.0,89698000.0,154410000.0,62482000.0,,,402450000.0,58742000.0,32715000.0,385290000.0,52702000.0,,94050000.0,1472400000.0,41119000.0,320380000.0,212010000.0,127760000.0,57768000.0,118970000.0,,277280000.0,3654500000.0,724440000.0,151760000.0,23328000.0,105100000.0,,169050000.0,13422000.0,534450000.0,1211000000.0,9083500.0,2072800.0,766050000.0,2395400000.0,85028000.0,151630000.0,761430000.0 +2020_05_14_20_11_Q-Exactive-HF-X-Orbitrap_6070,201910000.0,340090000.0,17824000.0,65642000.0,2925700000.0,,132750000.0,248790000.0,52687000.0,51681000.0,,,123410000.0,63201000.0,,100900000.0,,121430000.0,6848100000.0,43865000.0,593430000.0,45287000.0,19662000000.0,924290000.0,1033800000.0,16397000.0,43459000.0,136770000.0,168990000.0,33920000.0,2452300000.0,760720000.0,3214200000.0,1924400000.0,5163100000.0,55989000.0,336150000.0,7659800.0,1296700000.0,8243500000.0,99542000.0,87227000.0,,,,140530000.0,20201000.0,1249600000.0,5480200000.0,6069400000.0,1291900000.0,283460000.0,12874000.0,780860000.0,567620000.0,43006000.0,242630000.0,132480000.0,1680100000.0,460750000.0,214030000.0,7381500000.0,,52379000.0,,198570000.0,469790000.0,146880000.0,591740000.0,52293000.0,96050000.0,335460000.0,166210000.0,3125900000.0,82406000.0,112610000.0,,25488000.0,26990000.0,11878000.0,232340000.0,20527000.0,1208100000.0,29252000.0,32733000000.0,16903000.0,85705000.0,75968000.0,330870000.0,72775000.0,153430000.0,97628000.0,,57002000.0,901730000.0,,379230000.0,84282000.0,463560000.0,41368000.0,18919000.0,,1130800000.0,1195700000.0,2897600000.0,33878000.0,154760000.0,921900000.0,1037100000.0,35585000.0,1176100000.0,49923000.0,418680000.0,1571200000.0,,,103570000.0,10765000000.0,22843000.0,21435000.0,63945000000.0,608330000.0,231890000.0,1135600000.0,197370000.0,,31289000.0,343740000.0,256580000.0,789660000.0,348540000.0,264460000.0,8309000.0,79545000.0,26651000.0,79070000.0,39583000.0,53863000.0,,18150000.0,744290000.0,151940000.0,868440000.0,93431000.0,6161400.0,1364700000.0,45399000.0,,,101180000.0,411260000.0,14959000.0,21634000000.0,15321000.0,403430000.0,126660000.0,,249320000.0,466550000.0,44069000.0,40401000.0,375220000.0,510610000.0,21302000.0,,136640000.0,101810000.0,21539000.0,15094000.0,142800000.0,277940000.0,346630000.0,312740000.0,,198430000.0,367020000.0,128010000.0,1770000000.0,470870000.0,124700000.0,1386000000.0,68918000.0,8219700.0,44511000.0,1050000000.0,7921600000.0,,2949100000.0,138390000.0,90031000.0,210700000.0,38266000.0,,,456160000.0,142610000.0,43232000.0,427560000.0,60993000.0,39385000.0,106870000.0,1900500000.0,36610000.0,356990000.0,180290000.0,108810000.0,87537000.0,85719000.0,5182900.0,282830000.0,3274900000.0,833160000.0,118210000.0,12698000.0,88432000.0,17869000.0,236590000.0,,830940000.0,536380000.0,29234000.0,,800090000.0,2660400000.0,115320000.0,203540000.0,780340000.0 +2020_05_15_10_30_Q-Exactive-HF-X-Orbitrap_6070,582600000.0,416710000.0,30552000.0,117120000.0,6197900000.0,,168520000.0,392780000.0,111660000.0,58166000.0,,,191210000.0,15719000.0,38397000.0,181410000.0,5872000.0,145050000.0,11668000000.0,146300000.0,246870000.0,146360000.0,32630000000.0,1915500000.0,1746400000.0,80166000.0,65802000.0,111550000.0,302610000.0,99519000.0,4197100000.0,1234000000.0,3629700000.0,3812200000.0,7501300000.0,127920000.0,815680000.0,5942100.0,1821500000.0,13071000000.0,461070000.0,35091000.0,593730000.0,,,222980000.0,29812000.0,1294600000.0,8525000000.0,8781000000.0,2712300000.0,452670000.0,23450000.0,636970000.0,1178600000.0,50668000.0,596040000.0,212110000.0,2599500000.0,491320000.0,467530000.0,7689200000.0,,91058000.0,,221410000.0,489530000.0,242650000.0,853350000.0,81613000.0,92659000.0,140040000.0,89622000.0,4552000000.0,45395000.0,325450000.0,,150660000.0,,101520000.0,368360000.0,34367000.0,1265500000.0,32932000.0,49930000000.0,43353000.0,184870000.0,88694000.0,453700000.0,139890000.0,469670000.0,77386000.0,,64116000.0,1395900000.0,3088000000.0,596100000.0,113310000.0,500290000.0,82852000.0,21169000.0,,1551500000.0,1568600000.0,3405300000.0,132620000.0,221470000.0,1515300000.0,1661300000.0,60225000.0,2086900000.0,74010000.0,391470000.0,3262500000.0,59470000.0,,250550000.0,12895000000.0,55353000.0,10338000.0,90691000000.0,1162600000.0,437880000.0,1261400000.0,419480000.0,15510000.0,45152000.0,541040000.0,581170000.0,1100900000.0,565220000.0,463630000.0,12651000.0,194270000.0,28474000.0,149080000.0,80229000.0,,68707000.0,39195000.0,1115100000.0,250430000.0,1235600000.0,192250000.0,,466130000.0,41507000.0,107740000.0,,227710000.0,545230000.0,26080000.0,30607000000.0,58072000.0,769120000.0,144320000.0,,537730000.0,693130000.0,100020000.0,249450000.0,445580000.0,885390000.0,79854000.0,58993000.0,67756000.0,372230000.0,39068000.0,,227880000.0,285020000.0,241800000.0,532260000.0,,174380000.0,781650000.0,236070000.0,2880100000.0,968700000.0,190840000.0,1629200000.0,107090000.0,22542000.0,79600000.0,950020000.0,15848000000.0,,4154200000.0,278290000.0,210640000.0,331880000.0,237030000.0,,,1062500000.0,223780000.0,84210000.0,642340000.0,119130000.0,4404000.0,143220000.0,3232900000.0,51476000.0,556510000.0,268610000.0,261040000.0,238150000.0,223210000.0,24335000.0,702330000.0,7043500000.0,715510000.0,149260000.0,84527000.0,145700000.0,109880000.0,224050000.0,54878000.0,906460000.0,1087400000.0,75817000.0,,1228300000.0,3312700000.0,222630000.0,235390000.0, +2020_05_20_12_33_Q-Exactive-HF-X-Orbitrap_6070,360590000.0,137000000.0,26866000.0,50586000.0,4375800000.0,,71038000.0,334000000.0,31481000.0,79784000.0,,,178500000.0,84431000.0,,209180000.0,13718000.0,85967000.0,8450300000.0,66006000.0,130320000.0,8419900.0,19294000000.0,1182300000.0,1081900000.0,38565000.0,8408200.0,33747000.0,173630000.0,71288000.0,2080900000.0,573720000.0,2169700000.0,2007600000.0,4125200000.0,53767000.0,706720000.0,34739000.0,1573800000.0,7948300000.0,271220000.0,28040000.0,4590400000.0,,,107430000.0,11324000.0,1072200000.0,5058000000.0,5879700000.0,2096600000.0,220480000.0,10854000.0,978200000.0,452210000.0,40397000.0,293450000.0,145260000.0,1648900000.0,218870000.0,205690000.0,9343000000.0,,44617000.0,,133850000.0,476860000.0,152470000.0,429780000.0,67377000.0,46727000.0,32538000.0,91680000.0,3125000000.0,,170080000.0,2139400000.0,33772000.0,,26554000.0,278900000.0,,1242200000.0,36666000.0,45182000000.0,,48363000.0,98683000.0,338370000.0,27319000.0,256570000.0,71336000.0,,,1140800000.0,,365400000.0,41656000.0,319230000.0,39949000.0,14567000.0,,704360000.0,1203500000.0,2643000000.0,37622000.0,125800000.0,833620000.0,964110000.0,51467000.0,1906200000.0,44014000.0,273040000.0,1552200000.0,118770000.0,10438000.0,159000000.0,10828000000.0,14559000.0,22636000.0,59466000000.0,1113500000.0,224760000.0,1131000000.0,588690000.0,,,252290000.0,322110000.0,840030000.0,339150000.0,401820000.0,,138040000.0,,38351000.0,58149000.0,88449000.0,33389000.0,20247000.0,534520000.0,162870000.0,1425700000.0,104770000.0,,243720000.0,23983000.0,47400000.0,,83087000.0,446710000.0,25626000.0,21133000000.0,25857000.0,592220000.0,193960000.0,,390060000.0,336540000.0,64484000.0,19519000.0,407620000.0,813790000.0,72152000.0,,96295000.0,119100000.0,24770000.0,19424000.0,123290000.0,244640000.0,213520000.0,491950000.0,,141280000.0,481550000.0,94211000.0,1881700000.0,698960000.0,90442000.0,1412000000.0,57683000.0,,,1305200000.0,8253100000.0,,4311300000.0,190280000.0,107860000.0,268840000.0,13817000.0,14066000000.0,5794400.0,393610000.0,111300000.0,6722200.0,327590000.0,30643000.0,29239000.0,82211000.0,2618900000.0,56065000.0,227930000.0,116790000.0,95772000.0,53342000.0,129670000.0,,317390000.0,1887100000.0,630740000.0,125160000.0,33659000.0,175920000.0,10891000.0,154070000.0,18349000.0,584600000.0,966530000.0,45874000.0,,790720000.0,2323100000.0,78795000.0,132320000.0, +2020_05_20_15_35_Q-Exactive-HF-X-Orbitrap_6070,340940000.0,270900000.0,57264000.0,77686000.0,3713400000.0,,86760000.0,174620000.0,81286000.0,139480000.0,,402330000.0,126140000.0,62124000.0,,283010000.0,29132000.0,142390000.0,8966900000.0,144180000.0,324840000.0,58002000.0,28727000000.0,859470000.0,1330900000.0,43455000.0,66945000.0,48609000.0,102190000.0,92276000.0,2872800000.0,1443200000.0,3487900000.0,3253600000.0,6588200000.0,94769000.0,583170000.0,5568800.0,1422300000.0,12472000000.0,362550000.0,65544000.0,,,,188960000.0,20524000.0,1134300000.0,6915900000.0,7589800000.0,2037100000.0,465460000.0,24786000.0,445510000.0,634510000.0,92648000.0,403950000.0,139200000.0,2214200000.0,589870000.0,317520000.0,7485200000.0,42058000.0,58144000.0,,239060000.0,891370000.0,307140000.0,921130000.0,74916000.0,133810000.0,101180000.0,97862000.0,3542700000.0,16694000.0,155510000.0,2933200000.0,112850000.0,34238000.0,57957000.0,234780000.0,21141000.0,2651400000.0,35192000.0,38619000000.0,16300000.0,41827000.0,70954000.0,420090000.0,47691000.0,245970000.0,87073000.0,,49335000.0,2187400000.0,,252060000.0,131080000.0,450320000.0,41174000.0,,,1097400000.0,1470300000.0,3594100000.0,68766000.0,261990000.0,1287700000.0,1449900000.0,89004000.0,1634600000.0,116280000.0,431410000.0,1291900000.0,105610000.0,15625000.0,187370000.0,13661000000.0,33162000.0,18117000.0,93400000000.0,,2273700000.0,1428900000.0,381280000.0,,,370520000.0,269160000.0,1379900000.0,459110000.0,679800000.0,62697000.0,134740000.0,,55936000.0,119210000.0,136160000.0,41956000.0,126420000.0,709130000.0,107960000.0,1515900000.0,45425000.0,16212000.0,405380000.0,28567000.0,101980000.0,6578500.0,146110000.0,458260000.0,82969000.0,23393000000.0,83637000.0,744350000.0,104150000.0,,377480000.0,461120000.0,103950000.0,74421000.0,526980000.0,906890000.0,,49099000.0,132730000.0,242230000.0,21743000.0,29006000.0,140970000.0,168400000.0,319080000.0,445370000.0,,298330000.0,526480000.0,194380000.0,2623500000.0,693630000.0,190400000.0,1683000000.0,28943000.0,18156000.0,32254000.0,,9051200000.0,63369000.0,4542400000.0,158370000.0,145560000.0,327720000.0,61657000.0,26246000000.0,28022000.0,659270000.0,226120000.0,41713000.0,374860000.0,43865000.0,,218830000.0,2016000000.0,70841000.0,393680000.0,190100000.0,138130000.0,124030000.0,254800000.0,148540000.0,473140000.0,5772600000.0,805220000.0,196030000.0,40800000.0,110680000.0,22402000.0,178590000.0,27864000.0,669830000.0,955900000.0,34669000.0,,965180000.0,3573300000.0,128340000.0,336480000.0, +2020_05_22_14_57_Q-Exactive-HF-X-Orbitrap_6070,169260000.0,184990000.0,74627000.0,87377000.0,4241900000.0,,205340000.0,335500000.0,132680000.0,62444000.0,,,263530000.0,,,151210000.0,5087000.0,196460000.0,10331000000.0,108610000.0,162810000.0,59376000.0,32944000000.0,966770000.0,1121200000.0,87790000.0,46291000.0,116990000.0,150320000.0,73448000.0,4109500000.0,826270000.0,4482000000.0,2335800000.0,6795600000.0,53806000.0,445800000.0,,1725000000.0,10300000000.0,123920000.0,138500000.0,,,,134730000.0,25947000.0,1136200000.0,7607600000.0,6793500000.0,985650000.0,416310000.0,6377400.0,985120000.0,735120000.0,63852000.0,366510000.0,162210000.0,2792000000.0,763450000.0,235700000.0,5776900000.0,32263000.0,31884000.0,,271740000.0,453020000.0,313820000.0,633720000.0,103830000.0,93268000.0,114570000.0,200910000.0,6887400000.0,101150000.0,31358000.0,2050800000.0,38436000.0,42347000.0,,207380000.0,36625000.0,1655500000.0,42981000.0,44176000000.0,24307000.0,54728000.0,119700000.0,457690000.0,19653000.0,276140000.0,45172000.0,,46171000.0,2846800000.0,,530640000.0,28051000.0,630170000.0,71078000.0,38608000.0,,1193100000.0,1791600000.0,4134800000.0,37650000.0,168030000.0,1448500000.0,532290000.0,40693000.0,1668900000.0,62147000.0,506820000.0,1968000000.0,41097000.0,,153690000.0,16525000000.0,34386000.0,62865000.0,77097000000.0,,356840000.0,952920000.0,366650000.0,,,262480000.0,201940000.0,1120600000.0,542040000.0,583190000.0,53022000.0,67471000.0,12130000.0,104790000.0,47651000.0,135760000.0,,36842000.0,345480000.0,197790000.0,942060000.0,,,2466400000.0,76626000.0,73071000.0,,103250000.0,637540000.0,27090000.0,33845000000.0,,725090000.0,155030000.0,20310000.0,293470000.0,544350000.0,58083000.0,160880000.0,331300000.0,747840000.0,69659000.0,,,69822000.0,43297000.0,,175930000.0,225720000.0,421780000.0,331120000.0,,185370000.0,429550000.0,188760000.0,2320800000.0,824830000.0,249860000.0,1324600000.0,46749000.0,,35192000.0,213230000.0,8675900000.0,,3000000000.0,255680000.0,71206000.0,254950000.0,74144000.0,,6592900.0,,99111000.0,259490000.0,353100000.0,105360000.0,11075000.0,91262000.0,2040000000.0,60776000.0,529370000.0,224300000.0,229830000.0,135180000.0,144980000.0,,495720000.0,3206100000.0,1238100000.0,259960000.0,32162000.0,94588000.0,18545000.0,187980000.0,25235000.0,856280000.0,1088000000.0,89141000.0,,1348300000.0,3578900000.0,123370000.0,255880000.0, +2020_05_22_17_43_Q-Exactive-HF-X-Orbitrap_6070,454540000.0,339690000.0,40461000.0,125840000.0,5351300000.0,8699000.0,178640000.0,230050000.0,101870000.0,53640000.0,,,277870000.0,28772000.0,,238740000.0,,188210000.0,10363000000.0,125150000.0,184010000.0,61930000.0,30697000000.0,1499200000.0,1570600000.0,113550000.0,33272000.0,102330000.0,355660000.0,106310000.0,4055400000.0,1299600000.0,3649400000.0,3204900000.0,7498300000.0,88132000.0,717320000.0,,1999400000.0,10209000000.0,284390000.0,68531000.0,,,,194780000.0,,1549300000.0,9334900000.0,8894900000.0,1681100000.0,443780000.0,,1033100000.0,807220000.0,66741000.0,542640000.0,161460000.0,2737600000.0,565390000.0,289900000.0,8738800000.0,,58166000.0,,564040000.0,619590000.0,306000000.0,910190000.0,92915000.0,130530000.0,75141000.0,141900000.0,5067600000.0,112500000.0,201010000.0,2471100000.0,12989000.0,22537000.0,33675000.0,304930000.0,14060000.0,1758400000.0,31467000.0,40136000000.0,39488000.0,133060000.0,368180000.0,490440000.0,57743000.0,335050000.0,120750000.0,,58426000.0,2486300000.0,,453220000.0,72844000.0,787050000.0,65410000.0,20722000.0,,1035700000.0,1813800000.0,4733000000.0,64877000.0,377640000.0,1348900000.0,1268100000.0,109630000.0,1648000000.0,75778000.0,559450000.0,2045600000.0,,,243580000.0,15157000000.0,12529000.0,37332000.0,86502000000.0,,2912600000.0,1495600000.0,407130000.0,,,405690000.0,296040000.0,1481900000.0,633220000.0,813100000.0,28173000.0,144800000.0,34278000.0,356610000.0,86166000.0,65819000.0,60951000.0,38428000.0,425820000.0,189240000.0,1656400000.0,128990000.0,,520890000.0,76299000.0,203710000.0,,121260000.0,659720000.0,63477000.0,29193000000.0,35236000.0,734100000.0,104620000.0,16800000.0,461620000.0,605930000.0,145050000.0,170390000.0,622530000.0,741290000.0,22584000.0,19836000.0,103680000.0,188850000.0,19448000.0,,280270000.0,318030000.0,272260000.0,585550000.0,,355720000.0,611420000.0,191130000.0,2379200000.0,904840000.0,234350000.0,1901500000.0,96314000.0,27867000.0,60138000.0,1350300000.0,13055000000.0,12521000.0,4300600000.0,327190000.0,183820000.0,315690000.0,149130000.0,30710000000.0,44398000.0,,275660000.0,21061000.0,516520000.0,114680000.0,,130290000.0,2325300000.0,87039000.0,591360000.0,115100000.0,263630000.0,192380000.0,153270000.0,11820000.0,327210000.0,5585800000.0,641150000.0,134910000.0,34150000.0,191140000.0,34056000.0,229030000.0,15638000.0,1026000000.0,953800000.0,,,1284500000.0,3326300000.0,97477000.0,246850000.0, +2020_05_26_14_20_Q-Exactive-HF-X-Orbitrap_6070,523720000.0,468420000.0,59944000.0,78329000.0,6624300000.0,,417370000.0,483970000.0,243450000.0,103920000.0,,,364970000.0,36235000.0,,289780000.0,,121840000.0,19743000000.0,77723000.0,261440000.0,229130000.0,45390000000.0,1915700000.0,2187400000.0,65955000.0,29328000.0,208260000.0,311150000.0,51453000.0,5985500000.0,1700500000.0,5921600000.0,3640900000.0,11803000000.0,166320000.0,3392200000.0,12641000.0,4175200000.0,24005000000.0,538140000.0,137530000.0,,,,454940000.0,26111000.0,2387100000.0,14862000000.0,14094000000.0,3014900000.0,869410000.0,,480830000.0,1158700000.0,86181000.0,589290000.0,152380000.0,3075200000.0,1324500000.0,420860000.0,19372000000.0,,135310000.0,,222910000.0,1550300000.0,634470000.0,1256200000.0,156590000.0,147960000.0,67170000.0,597940000.0,7580800000.0,183730000.0,300980000.0,,67439000.0,,47176000.0,486380000.0,34402000.0,2586900000.0,115940000.0,92561000000.0,35467000.0,154080000.0,90392000.0,506750000.0,52819000.0,627530000.0,169770000.0,,56725000.0,4694800000.0,,567160000.0,120320000.0,1023800000.0,156870000.0,50725000.0,,2273400000.0,3077700000.0,4607600000.0,191920000.0,523540000.0,2258900000.0,1970400000.0,82416000.0,2374700000.0,140070000.0,852050000.0,4231700000.0,86706000.0,17548000.0,251940000.0,26953000000.0,54493000.0,25395000.0,159580000000.0,,3521400000.0,2088600000.0,391550000.0,,27316000.0,650640000.0,729520000.0,1421600000.0,930500000.0,839400000.0,47302000.0,129630000.0,40591000.0,184800000.0,211170000.0,243710000.0,,52882000.0,1829100000.0,324690000.0,2610300000.0,305530000.0,,4298000000.0,89678000.0,196310000.0,,104110000.0,1261400000.0,49300000.0,50402000000.0,94647000.0,1593600000.0,295340000.0,,853960000.0,862480000.0,199200000.0,16432000.0,965410000.0,1557100000.0,,36554000.0,255880000.0,388910000.0,,58568000.0,392100000.0,481180000.0,893600000.0,916530000.0,,508950000.0,839820000.0,202270000.0,4932400000.0,1472500000.0,197900000.0,2636200000.0,244810000.0,54868000.0,138020000.0,1283100000.0,19468000000.0,62570000.0,7129600000.0,354300000.0,212430000.0,247330000.0,147640000.0,56014000000.0,55036000.0,1612600000.0,77832000.0,69398000.0,983640000.0,98923000.0,,197820000.0,3149100000.0,38653000.0,774350000.0,405010000.0,478560000.0,372520000.0,120430000.0,,877410000.0,6858300000.0,1827900000.0,357900000.0,25238000.0,238530000.0,54183000.0,510410000.0,18946000.0,1807400000.0,2431200000.0,155490000.0,,1951700000.0,6647300000.0,211410000.0,540610000.0,2463200000.0 +2020_05_27_13_57_Q-Exactive-HF-X-Orbitrap_6070,1019000000.0,949030000.0,316810000.0,364680000.0,10686000000.0,63112000.0,853670000.0,1228500000.0,470120000.0,281780000.0,,,727200000.0,146030000.0,,784800000.0,115550000.0,658060000.0,33508000000.0,393460000.0,807430000.0,352400000.0,83324000000.0,6411600000.0,5812000000.0,336700000.0,203960000.0,400880000.0,733310000.0,384890000.0,10038000000.0,3758600000.0,13984000000.0,11829000000.0,23673000000.0,397450000.0,2752800000.0,122660000.0,8163700000.0,35321000000.0,1135100000.0,341950000.0,2323600000.0,,25574000.0,862240000.0,44097000.0,5740400000.0,25224000000.0,28252000000.0,5878700000.0,1476800000.0,19899000.0,1298600000.0,3119500000.0,309410000.0,1657400000.0,711770000.0,10382000000.0,1410100000.0,1310300000.0,27997000000.0,147090000.0,272430000.0,,1120600000.0,1746700000.0,1278700000.0,3365500000.0,396550000.0,430060000.0,478660000.0,523440000.0,15408000000.0,270320000.0,926060000.0,,299560000.0,31736000.0,219750000.0,1415000000.0,69582000.0,4452300000.0,185230000.0,107330000000.0,238440000.0,385170000.0,608120000.0,1677400000.0,197340000.0,1021700000.0,149710000.0,,378730000.0,5971000000.0,6373500000.0,1551000000.0,203990000.0,2272000000.0,321400000.0,106410000.0,,3940200000.0,4982800000.0,12796000000.0,200530000.0,917330000.0,3472100000.0,4164300000.0,134710000.0,4277900000.0,359380000.0,2520400000.0,9336200000.0,164160000.0,206840000.0,903030000.0,49385000000.0,184370000.0,138280000.0,251120000000.0,3285300000.0,10664000000.0,5706500000.0,1640900000.0,41251000.0,,1328200000.0,1239600000.0,4565500000.0,2503200000.0,3114600000.0,143810000.0,489850000.0,188030000.0,308910000.0,433810000.0,399560000.0,197230000.0,319010000.0,2834300000.0,813940000.0,3826300000.0,371640000.0,74686000.0,1911900000.0,196170000.0,507590000.0,,652560000.0,1781800000.0,94849000.0,70227000000.0,193020000.0,1806500000.0,694410000.0,46050000.0,1886300000.0,2821000000.0,150470000.0,610430000.0,2739200000.0,3469700000.0,152690000.0,102920000.0,244470000.0,1075200000.0,84438000.0,196080000.0,741060000.0,1321200000.0,773950000.0,1563900000.0,,1442600000.0,1735500000.0,1133300000.0,9230700000.0,3181400000.0,914070000.0,3814300000.0,395190000.0,,327750000.0,5192200000.0,34831000000.0,105190000.0,12209000000.0,602900000.0,529490000.0,1466400000.0,702280000.0,,92812000.0,3330800000.0,449840000.0,366920000.0,2266900000.0,362600000.0,82386000.0,725730000.0,7029300000.0,268180000.0,1754200000.0,717320000.0,882690000.0,641400000.0,688740000.0,166790000.0,2217100000.0,18861000000.0,3693900000.0,820620000.0,78884000.0,800530000.0,193000000.0,734490000.0,127730000.0,3639900000.0,3592600000.0,,,4435800000.0,14556000000.0,,811370000.0, +2020_05_28_04_06_Q-Exactive-HF-X-Orbitrap_6070,1507800000.0,570540000.0,264310000.0,476130000.0,14862000000.0,63117000.0,1216900000.0,1377700000.0,519730000.0,410430000.0,,,1458700000.0,179160000.0,,679240000.0,,805880000.0,43488000000.0,734840000.0,1025000000.0,417130000.0,97880000000.0,7256600000.0,6383500000.0,288360000.0,,474180000.0,741910000.0,486070000.0,12889000000.0,4316700000.0,17174000000.0,11522000000.0,27240000000.0,405290000.0,2409900000.0,123840000.0,10796000000.0,45876000000.0,1668200000.0,408910000.0,2658400000.0,,,1406100000.0,164780000.0,7013300000.0,30386000000.0,32378000000.0,7124800000.0,2350200000.0,116580000.0,3063300000.0,3769100000.0,250420000.0,1658200000.0,780670000.0,12827000000.0,1992800000.0,3162000000.0,30848000000.0,162800000.0,370090000.0,,1054800000.0,2684400000.0,1421900000.0,4173300000.0,498970000.0,437660000.0,4156700000.0,731790000.0,17371000000.0,479100000.0,565010000.0,,341150000.0,251620000.0,150990000.0,1195600000.0,185440000.0,7427400000.0,112380000.0,131690000000.0,236640000.0,573080000.0,285150000.0,1574000000.0,226620000.0,1213900000.0,289310000.0,,829730000.0,3723100000.0,12845000000.0,1462200000.0,590100000.0,2609100000.0,262500000.0,214960000.0,,4680300000.0,5026300000.0,16071000000.0,312250000.0,1376200000.0,5198100000.0,4820000000.0,223090000.0,7011800000.0,381850000.0,2586700000.0,10547000000.0,167690000.0,98290000.0,865200000.0,61312000000.0,305800000.0,199680000.0,314580000000.0,58647000.0,12062000000.0,6131700000.0,2291400000.0,37397000.0,,1258100000.0,1980500000.0,4815000000.0,3774400000.0,3251500000.0,143610000.0,721600000.0,177100000.0,469850000.0,345640000.0,552520000.0,271250000.0,263000000.0,4416000000.0,833690000.0,4759800000.0,212340000.0,107850000.0,7211300000.0,429720000.0,81160000.0,75914000.0,951870000.0,2646100000.0,350690000.0,93467000000.0,187190000.0,2612000000.0,789870000.0,75245000.0,1877600000.0,4078200000.0,216890000.0,499180000.0,2215300000.0,3706200000.0,172750000.0,50708000.0,543920000.0,1158800000.0,97121000.0,134410000.0,807140000.0,1567900000.0,902190000.0,2132900000.0,,2213300000.0,2326100000.0,887830000.0,11467000000.0,3746800000.0,1151800000.0,5910500000.0,586790000.0,102980000.0,263490000.0,2494700000.0,33627000000.0,232720000.0,12946000000.0,1302500000.0,661230000.0,1192900000.0,712800000.0,84861000000.0,145560000.0,2491000000.0,357160000.0,406680000.0,2883300000.0,528600000.0,52787000.0,972780000.0,9602100000.0,203560000.0,2056900000.0,808770000.0,1126300000.0,524000000.0,778980000.0,339660000.0,2489300000.0,21105000000.0,4731400000.0,1012300000.0,102540000.0,1130800000.0,204690000.0,913580000.0,66807000.0,4211300000.0,5002300000.0,,48645000.0,5759300000.0,15124000000.0,508050000.0,1053200000.0,4089000000.0 +2020_06_01_10_22_Q-Exactive-HF-X-Orbitrap_6070,,,,17836000.0,10572000000.0,,199240000.0,34746000.0,99474000.0,156480000.0,119800000.0,,,108500000.0,20522000.0,220060000.0,,,5038900000.0,21121000.0,225930000.0,,55890000000.0,92586000.0,1083700000.0,,,,110370000.0,,1504300000.0,839470000.0,7579300000.0,1146900000.0,9507900000.0,,769910000.0,22056000.0,2012700000.0,9265800000.0,188980000.0,,,168870000.0,,25760000.0,24172000.0,2080500000.0,12311000000.0,7094300000.0,2538300000.0,35706000.0,17511000.0,4442900000.0,316340000.0,,106420000.0,82895000.0,3157300000.0,342340000.0,191550000.0,11440000000.0,,55566000.0,14101000.0,320900000.0,286840000.0,2087600000.0,1136800000.0,,26832000.0,,127920000.0,4076800000.0,,219870000.0,2855600000.0,60635000.0,,318940000.0,169310000.0,,975950000.0,28494000.0,133570000000.0,,,23302000.0,93731000.0,20400000.0,41936000.0,,45213000.0,,4292200000.0,2193700000.0,159780000.0,,256160000.0,,21995000.0,374450000.0,743300000.0,1287100000.0,1091500000.0,,100020000.0,837820000.0,1484900000.0,109860000.0,1346600000.0,,667390000.0,811260000.0,442460000.0,18193000.0,109520000.0,20606000000.0,,,146000000000.0,69009000.0,2737700000.0,1777400000.0,307110000.0,,,299140000.0,1047800000.0,1338600000.0,295020000.0,527140000.0,120140000.0,105230000.0,132570000.0,80978000.0,,,,27366000.0,155280000.0,68486000.0,3712000000.0,46604000.0,151690000.0,43021000.0,,35227000.0,15968000.0,38069000.0,827510000.0,47698000.0,89029000000.0,,1065100000.0,204950000.0,,418300000.0,547990000.0,,20509000.0,579520000.0,108340000.0,70205000.0,,160010000.0,81327000.0,,,112660000.0,1011200000.0,214170000.0,68197000.0,307220000.0,123280000.0,232540000.0,7605400.0,1620500000.0,307580000.0,61589000.0,914960000.0,28309000.0,35997000.0,79649000.0,,14000000000.0,,1061500000.0,197900000.0,31127000.0,34161000.0,205860000.0,1444600000.0,,202890000.0,1083400000.0,,922180000.0,11287000.0,73979000.0,147030000.0,1983500000.0,334740000.0,62519000.0,,46885000.0,32036000.0,,,1191800000.0,5609300000.0,1730600000.0,547050000.0,,62691000.0,64152000.0,242930000.0,58256000.0,1110900000.0,645740000.0,,,300380000.0,4160400000.0,,71290000.0,8443600000.0 +2020_06_01_15_41_Q-Exactive-HF-X-Orbitrap_6070,254420000.0,,104380000.0,19899000.0,15447000000.0,50842000.0,443570000.0,256320000.0,,,435750000.0,2979100000.0,,342820000.0,,204990000.0,,229960000.0,13234000000.0,388420000.0,687740000.0,,91447000000.0,137010000.0,1107700000.0,,71906000.0,29181000.0,226790000.0,116840000.0,4221200000.0,577430000.0,11947000000.0,1571100000.0,16846000000.0,,1743300000.0,,3331800000.0,21713000000.0,344950000.0,,,319700000.0,,,74024000.0,5525300000.0,24892000000.0,15814000000.0,3677700000.0,276130000.0,54614000.0,7656000000.0,552540000.0,32190000.0,231940000.0,,3931000000.0,1703500000.0,515810000.0,16008000000.0,,151860000.0,22471000.0,401220000.0,443730000.0,4946300000.0,3016100000.0,,30389000.0,70199000.0,1124800000.0,8993600000.0,84948000.0,532650000.0,,,,436480000.0,402330000.0,,2340800000.0,,174920000000.0,,119990000.0,198680000.0,148480000.0,30222000.0,,93136000.0,152270000.0,,8029600000.0,,613070000.0,,668360000.0,,249440000.0,1134400000.0,2677200000.0,2989100000.0,6662300000.0,,289250000.0,2119600000.0,2408400000.0,127320000.0,1124500000.0,,1999700000.0,2498800000.0,709030000.0,102200000.0,,37747000000.0,,,256870000000.0,,7718900000.0,3682300000.0,1624700000.0,,,255520000.0,1334000000.0,2474900000.0,895640000.0,1383800000.0,74830000.0,312210000.0,324900000.0,356400000.0,,,,19302000.0,451100000.0,147360000.0,3520900000.0,112510000.0,320670000.0,314190000.0,184300000.0,139900000.0,,37017000.0,1818600000.0,64943000.0,162210000000.0,,901020000.0,381830000.0,,980500000.0,932820000.0,226990000.0,,751260000.0,462530000.0,152950000.0,,237470000.0,169550000.0,,35626000.0,203220000.0,2196500000.0,496260000.0,90437000.0,76447000.0,332890000.0,217480000.0,,2915500000.0,759840000.0,215930000.0,2419400000.0,26689000.0,157800000.0,88998000.0,3519300000.0,30647000000.0,,1915700000.0,528380000.0,202750000.0,53035000.0,201400000.0,2844900000.0,,767640000.0,1314400000.0,,2175300000.0,32211000.0,264870000.0,366150000.0,2550400000.0,262550000.0,93648000.0,,228220000.0,55059000.0,67988000.0,72113000.0,2164900000.0,10665000000.0,3667800000.0,1083600000.0,,108100000.0,51431000.0,316450000.0,21808000.0,2909900000.0,1214500000.0,220760000.0,,621960000.0,8016300000.0,,,15962000000.0 +2020_06_02_09_41_Q-Exactive-HF-X-Orbitrap_6070,410960000.0,470610000.0,105770000.0,178810000.0,7460000000.0,,435480000.0,451120000.0,227090000.0,123530000.0,,,426780000.0,,,316620000.0,,118120000.0,20763000000.0,145580000.0,399480000.0,66115000.0,54795000000.0,2354200000.0,2643100000.0,141560000.0,185530000.0,312700000.0,557050000.0,135690000.0,5924400000.0,2094600000.0,7501200000.0,3965800000.0,13928000000.0,173810000.0,1190200000.0,,2920200000.0,17913000000.0,537420000.0,,10973000000.0,,,411490000.0,93824000.0,2146800000.0,14785000000.0,14258000000.0,2086000000.0,858930000.0,,631150000.0,1337000000.0,149980000.0,721090000.0,265890000.0,4596700000.0,1278900000.0,435860000.0,13410000000.0,27760000.0,87124000.0,,458900000.0,858060000.0,704180000.0,1415700000.0,187540000.0,279350000.0,1706800000.0,233930000.0,7674400000.0,329900000.0,190330000.0,4005500000.0,116980000.0,15495000.0,57531000.0,784270000.0,32068000.0,3696900000.0,129810000.0,84037000000.0,,211740000.0,99351000.0,717940000.0,59564000.0,609790000.0,,,74848000.0,791610000.0,,486620000.0,155990000.0,990450000.0,165240000.0,25773000.0,,2266300000.0,3332700000.0,6299700000.0,135160000.0,619720000.0,1992100000.0,2399700000.0,175590000.0,2662300000.0,121930000.0,1183700000.0,3869400000.0,55012000.0,,171790000.0,25740000000.0,103080000.0,67035000.0,193730000000.0,68197000.0,760220000.0,2296000000.0,619610000.0,,154170000.0,733490000.0,672620000.0,2436800000.0,1219500000.0,523120000.0,18541000.0,283780000.0,41076000.0,185930000.0,80195000.0,192050000.0,68340000.0,61410000.0,1476800000.0,272240000.0,1637400000.0,62025000.0,32572000.0,685070000.0,41503000.0,121840000.0,,272370000.0,1028400000.0,60642000.0,58256000000.0,93905000.0,1276000000.0,152090000.0,13482000.0,741870000.0,1153200000.0,225480000.0,168330000.0,716300000.0,1637000000.0,63893000.0,37966000.0,148200000.0,256970000.0,63575000.0,,385570000.0,672410000.0,575820000.0,689340000.0,,506290000.0,1102100000.0,239780000.0,4075400000.0,1205900000.0,581420000.0,2167300000.0,212030000.0,38825000.0,42891000.0,1494300000.0,17199000000.0,30596000.0,5622000000.0,537920000.0,342180000.0,248910000.0,297790000.0,1140100000.0,47740000.0,1109100000.0,318980000.0,40020000.0,1087300000.0,172680000.0,,212850000.0,3391900000.0,129080000.0,719610000.0,332810000.0,290970000.0,195110000.0,517040000.0,,889360000.0,11908000000.0,2391500000.0,484240000.0,69790000.0,345580000.0,73200000.0,429250000.0,32705000.0,1369300000.0,1753700000.0,211680000.0,,1950400000.0,6681700000.0,585320000.0,574460000.0, From 0bee424e765a43c2c5caad4d04bae5883261a654 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 16 Nov 2023 09:04:54 +0100 Subject: [PATCH 49/70] :bug: execute one-by-one, show errors in main process --- .github/workflows/ci.yaml | 2 +- project/workflow/Snakefile | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 48e101087..3fe7ca96b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -65,7 +65,7 @@ jobs: run: | cd project snakemake -p -c1 --configfile config/single_dev_dataset/example/config.yaml -n - snakemake -p -c2 -k --configfile config/single_dev_dataset/example/config.yaml + snakemake -p -c1 -k --configfile config/single_dev_dataset/example/config.yaml - name: Archive results uses: actions/upload-artifact@v3 with: diff --git a/project/workflow/Snakefile b/project/workflow/Snakefile index 41228991f..5d44661ae 100644 --- a/project/workflow/Snakefile +++ b/project/workflow/Snakefile @@ -120,8 +120,8 @@ rule train_NAGuideR_model: folder_experiment="{folder_experiment}", method="{method}", name="{method}", - log: - err="{folder_experiment}/01_1_train_NAGuideR_{method}.log", + # log: + # err="{folder_experiment}/01_1_train_NAGuideR_{method}.log", conda: "vaep" shell: @@ -129,7 +129,7 @@ rule train_NAGuideR_model: " -r train_split {input.train_split:q}" " -r method {params.method}" " -r folder_experiment {params.folder_experiment:q}" - " 2> {log.err}" + # " 2> {log.err}" " && jupyter nbconvert --to html {output.nb:q}" From 1b23b95fb7b131c08d90f31b3996372960c71ecd Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 16 Nov 2023 09:08:14 +0100 Subject: [PATCH 50/70] :bug: SeqKNN crashes with too few samples - is GSIMP fast enough (227-> ~1h)? - probably test GSIMP here once, then remove from "fast testing" workflow --- .../single_dev_dataset/example/split.yaml | 2 +- .../protein_groups_wide_N50_M454.csv | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 project/data/dev_datasets/HeLa_6070/protein_groups_wide_N50_M454.csv diff --git a/project/config/single_dev_dataset/example/split.yaml b/project/config/single_dev_dataset/example/split.yaml index 85e8faaef..46565d148 100644 --- a/project/config/single_dev_dataset/example/split.yaml +++ b/project/config/single_dev_dataset/example/split.yaml @@ -1,4 +1,4 @@ -FN_INTENSITIES: data/dev_datasets/HeLa_6070/protein_groups_wide_N50_M227.csv +FN_INTENSITIES: data/dev_datasets/HeLa_6070/protein_groups_wide_N50_M454.csv fn_rawfile_metadata: data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv sample_completeness: 0.5 feat_prevalence: 0.6 diff --git a/project/data/dev_datasets/HeLa_6070/protein_groups_wide_N50_M454.csv b/project/data/dev_datasets/HeLa_6070/protein_groups_wide_N50_M454.csv new file mode 100644 index 000000000..627406322 --- /dev/null +++ b/project/data/dev_datasets/HeLa_6070/protein_groups_wide_N50_M454.csv @@ -0,0 +1,51 @@ +Sample ID,COX6A1,GTF2A2,ALDOA,TRAPPC3,AXL,EYA3,HIST2H2AC;HIST2H2AA3,IGF2BP3,CRTAP,RNASEH2C,FCF1,DSCR3,INTS9,PRPF6,ARL6IP4,TMEM30A,COL14A1,EXOSC7,ARMCX3,MARCH5,KTN1,PPP1R13L,ARGLU1,NAT10,NRBP1,AKR1A1,TRMT2A,SNRPF,VWA9,GNAI1,AK3,TXNL4A,PRPF8,BGN,CDKN2AIP,AP2A2,FASN,LRSAM1,MCM3,SERF2,KIF21A,HIGD2A,APEX1,CUL4A,NPLOC4,NCAPD2,RANBP9,CCBL2,RAB6A,VPS33A,SAP30BP,UBA52;UBC;UBB;RPS27A,RRP1B,AP2M1,TMEM245,ELP4,AURKA,AQR,LIG3,RPL27A,CDK9,THYN1,CASK,CLPP,MRPS28,FN3KRP,STRN4,ATP1A1,ALDH2,PPIF,KIF4A,ANO6,RPTOR,ATP6V1H,NELFCD;TH1L,CDCA7L,COASY,DDX52,ARAF,CKAP4,PITPNA,FAM91A1,RDH13,SCRN2,PRKCDBP,INTS7,MGMT,COQ9,SLC38A2,SLC7A1,CGGBP1,LLGL1,MFN1,SRPK2,MBD2,AP2S1,RBM17,DYNLL2,CRK,ALDH16A1,YBX1,SRM,ACTL6A,LRP1,SNF8,RPLP1,UBP1,WDR18,AFF4,MRPL32,HMGB2,HMGB3,Em:AP000351.3;GSTT2;GSTT2B,SMOC1,UTRN,PPP4C,RFX5,UBA6,SARNP,WNK1,RFC3,NQO2,NT5DC2,DDX17,SLC25A19,SLC16A7,YTHDF1,CNDP2,EIF4EBP2,EXOSC10,WBP2,ECT2,PPP4R2,TRUB1,TMEM65,ARHGAP35,THOC6,DKFZp686J1372;TPM3,TSNAX;DISC1,GNPAT,MSH3,PPP1R14B,PRMT7,SF3B2,RPAP1,MTFP1,MRPL19,UFSP2,DCTN3,MALT1,STAG2,TSC22D1,KIAA1143,S100A16,ATP5J,PMPCA,NUP153,CCDC12,YWHAH,MCU,HDLBP,UHRF2,NIFK,POLR2J3;POLR2J;POLR2J2,ASB6,RPS6KA3,ISOC1,UBE2Z,MRPL39,NKRF,SCRN1,B4GALT1,WBSCR16,TMEM192,ANKZF1,SREK1IP1,RPL38,ITPR1,SEC23A,EPB41L1,C9orf64,PITHD1,PPP1R10,BYSL,COMMD5,CSTB,SETD3,TPR,COTL1,GPHN,NAE1,POLR2C,TMEM261,PSMD5,CENPH,EXOC1,GOT1,LUC7L3,PAPSS1,SMAP;C11orf58,DYNLRB1,KIAA1279,SEPT2,PRRC2B,SLC25A5,HOOK3,CHCHD4,C5orf51,FNTA,HSPG2,SURF6,GLE1,ELAVL1,PTGFRN,BRAT1,TUBG1;TUBG2,GSTM1,HSP90AB2P,USP5,GGA2,NEK7,RRP12,ADAM10,NR2C2AP,CFL1,PROCR,POLE4,OCRL,ATF7,SGSH,C16orf62,OXSR1,MRPS25,PAXBP1,RTN1,BCAT1,LRRC16A,PTRH2,CASP2,LARP4B,UBE4A,RPP38,WDR36,TRIP12,NUP107,DNM1,POLA1,VCP,GRSF1,TUFM,PROSC,KNOP1,ATF7IP,DCTN4,RNF114,NUDT9,P4HA1,NONO,NSMCE2,PIGS,NUP62,VPS13C,NEGR1,IPO7,DNAJB1,GMPR2,PAAF1,CHRAC1,NDUFAF4,CLIC1,LAMTOR1,WDR61,PGK1,PLS3,GBF1,MPP6,TNPO1,ACTR3,MTOR,VPS11,LIMCH1,CHAMP1,EIF3C;EIF3CL,CARM1,MTHFD2,ELOF1,JUNB,EPN1,DBN1,SNX3,PSMD8,HEATR6,TXN,GPN3,RPAP3,HSPH1,ZNF706,AHSA1,ABCB6,SUMO3,SF3A1,INPP1,TWISTNB,NANS,RPRD1A,MFAP1,DDX19A;DDX19B,PABPC1;PABPC3,MRPS9,ERAP1,CASC4,DTD1,CCDC58,TMED5,ATP13A1,CRTC3,DNAJC10,GAR1,SYNCRIP,ACAD9,RAB1B;RAB1C,GTF2I,COPS4,TRIM28,TMSB4X,NVL,CD99,PIH1D1,MAGT1,GCDH,EIF1B,PLEKHA2,SLC35A4,IPO11,AAR2,CCT3,GRPEL1,SYNGR2,ABHD11,COPG1,CSE1L,PPP2CA;PPP2CB,SLC7A5,TRMT10C,VPS29,COX6C,CTSD,MRE11A,DENR,ACTN1,SNRNP70,FARP1,RBM34,PTPN1,SH3BGRL3,NPEPPS,FAM195B,ARPC1A,NACC1,TRMT5,PXN,VTA1,ZC3H7B,ERP29,MRPS26,PRMT3,SEPT7,PDCD5,NPM3,RCN2,SMARCA1,ITGB1,GNG12,RTCA,SPG21,RAB35,MRPL51,GABARAPL2,PPAN;PPAN-P2RY11,EMC1,ATP5SL,LIPA,DNAJA4,LSM12,MRPL12,CAPZA1,RPS5,NIT2,NIPSNAP3A,DHX8,RPL18A,TNFAIP8,FHL3,MRPS35,PRPF38B,DPM3,UTP3,FKBP14,LSG1,FLOT2,EDC4,WDR33,ZNF326,KDM1A,SUCLG2,NRD1,DUSP12,SNAP29,GEMIN5,PPP3R1,IWS1,TIMM9,DNAJB4,DERL2,RPS2,SNX2,BPI,SMG8,DDAH2,BDH2,FHL1,POLR3A,LCMT1,POLR1A,ATIC,AVEN,TIMM23;TIMM23B,FLYWCH2,INF2,FAM21A;FAM21C,POR,SDF2L1,RPS7,PRKAA1,HSPA4,NDUFAF3,PSMD14,HN1L,FDXR,PTMS,TRAF2,CCDC50,PARVA,EIF4G1,MED4,DDX46,PODXL,RBM22,YIF1B,CSNK1A1,YY1,VWA8,IKBKB,CHMP1A +2019_12_18_14_35_Q-Exactive-HF-X-Orbitrap_6070,,,26334000000.0,221750000.0,,,,1144400000.0,385150000.0,68173000.0,60790000.0,,79071000.0,1484700000.0,52205000.0,105920000.0,,467030000.0,,100640000.0,2185500000.0,,125610000.0,2027600000.0,276210000.0,943060000.0,17604000.0,1060000000.0,82020000.0,21166000.0,84744000.0,64074000.0,4929300000.0,,141580000.0,182420000.0,27789000000.0,190830000.0,3159300000.0,,530620000.0,183330000.0,3389000000.0,928040000.0,431780000.0,1480000000.0,93783000.0,,,92406000.0,70097000.0,,827630000.0,462180000.0,17610000.0,38120000.0,56965000.0,181260000.0,430840000.0,4121600000.0,116440000.0,189160000.0,7352400.0,224970000.0,114360000.0,13363000.0,,4492000000.0,,663110000.0,148920000.0,12799000.0,38190000.0,132860000.0,216050000.0,,1400200000.0,278920000.0,9964800.0,2768600000.0,339280000.0,207350000.0,283660000.0,,,117080000.0,115610000.0,301030000.0,580420000.0,104190000.0,19964000.0,,132660000.0,231900000.0,31194000.0,84635000.0,254910000.0,33217000.0,268690000.0,90541000.0,5567800000.0,1920800000.0,677270000.0,,31860000.0,5298900000.0,,321070000.0,,57241000.0,490230000.0,99739000.0,,,,157840000.0,,279780000.0,1302800000.0,218170000.0,350940000.0,671270000.0,54131000.0,2756100000.0,111020000.0,,31864000.0,821880000.0,,617540000.0,,112580000.0,179750000.0,38637000.0,23485000.0,,247130000.0,8341600000.0,,14757000.0,44890000.0,312660000.0,93890000.0,2747000000.0,13171000.0,,192110000.0,36644000.0,14188000.0,,579530000.0,,125350000.0,122060000.0,382260000.0,1626700000.0,294490000.0,230250000.0,818890000.0,427270000.0,2111400000.0,,502040000.0,129440000.0,35344000.0,208710000.0,291540000.0,179620000.0,344880000.0,378680000.0,125520000.0,20713000.0,86122000.0,,34397000.0,,526750000.0,222710000.0,520620000.0,,90622000.0,12408000.0,65200000.0,727830000.0,,3678200000.0,70791000.0,3476600000.0,1744500000.0,85923000.0,234520000.0,88669000.0,98157000.0,1339900000.0,34628000.0,,1831600000.0,650750000.0,615110000.0,156080000.0,312840000.0,273110000.0,863560000.0,15057000.0,876150000.0,8712400.0,172310000.0,96523000.0,95068000.0,,326240000.0,111400000.0,2171900000.0,,289090000.0,685770000.0,,1617600000.0,1626600000.0,38034000.0,52534000.0,2162300000.0,109160000.0,42565000.0,11331000000.0,106720000.0,6877800.0,27780000.0,42155000.0,,,799620000.0,193880000.0,85313000.0,,,48206000.0,403990000.0,52727000.0,209860000.0,252070000.0,,1080400000.0,86757000.0,514310000.0,,136570000.0,10310000000.0,1479600000.0,10372000000.0,202380000.0,268430000.0,25882000.0,142650000.0,270160000.0,143990000.0,745050000.0,4287800000.0,185700000.0,214700000.0,724620000.0,,,4601700000.0,1212400000.0,,65495000.0,114720000.0,423050000.0,4299600000.0,575210000.0,340880000.0,17028000000.0,5655900000.0,679540000.0,203340000.0,3239900000.0,879960000.0,283360000.0,53465000.0,300860000.0,188570000.0,2472200000.0,213530000.0,643410000.0,43435000.0,,131230000.0,480020000.0,786620000.0,348060000.0,47282000.0,16340000000.0,21708000.0,570490000.0,8015200000.0,,3479000000.0,23265000.0,1529900000.0,2149300000.0,21005000.0,29487000.0,662490000.0,102670000.0,147250000.0,,,330350000.0,69806000.0,32472000.0,53678000.0,209520000.0,252970000.0,203950000.0,25913000.0,,191630000.0,8304000000.0,390910000.0,,2243800000.0,589610000.0,5356800000.0,,181990000.0,76059000.0,141330000.0,,43935000.0,,,92837000.0,446890000.0,159370000.0,12399000000.0,677760000.0,25285000.0,55043000.0,2104700000.0,9770700000.0,,1272300000.0,543670000.0,1048300000.0,733370000.0,1788800000.0,198480000.0,250740000.0,1918400000.0,1631500000.0,,191910000.0,443930000.0,254800000.0,2936700000.0,,26182000.0,115240000.0,39474000.0,127290000.0,286620000.0,5061300.0,1874400000.0,64267000.0,309810000.0,784620000.0,2530100000.0,1646600000.0,424620000.0,,433780000.0,291400000.0,105140000.0,134350000.0,147640000.0,43519000.0,165670000.0,,653610000.0,,46199000.0,144810000.0,,1061900000.0,1076800000.0,9974800000.0,236750000.0,27791000.0,135280000.0,3703500000.0,,49433000.0,190160000.0,18180000.0,106060000.0,99003000.0,,225930000.0,323250000.0,1008500000.0,47671000.0,453280000.0,296050000.0,575790000.0,1176400000.0,180840000.0,37935000.0,2067900000.0,75756000.0,101840000.0,140510000.0,319900000.0,,8173100000.0,319530000.0,,,,,20405000.0,110760000.0,34667000.0,355350000.0,4352000000.0,,,492470000.0,406360000.0,,2293100000.0,165950000.0,5462300000.0,155530000.0,8756500000.0,17358000.0,691890000.0,586910000.0,56763000.0,938680000.0,197980000.0,89162000.0,29172000.0,7329000000.0,62928000.0,2495800000.0,368600000.0,23691000.0,17144000.0,,,62607000.0,,86827000.0 +2019_12_19_19_48_Q-Exactive-HF-X-Orbitrap_6070,,18895000.0,25799000000.0,212240000.0,,7106500.0,,851160000.0,307160000.0,,10275000.0,,78610000.0,1061900000.0,58924000.0,51937000.0,,293740000.0,,15236000.0,1610100000.0,,,1806000000.0,201490000.0,1125700000.0,85676000.0,685910000.0,139540000.0,33583000.0,44735000.0,,4389900000.0,,,81286000.0,21593000000.0,109620000.0,3231800000.0,64888000.0,365470000.0,,1981600000.0,702990000.0,407390000.0,1296200000.0,107660000.0,76180000.0,,58014000.0,25491000.0,,627900000.0,215720000.0,14620000.0,7923700.0,,258510000.0,246620000.0,4191400000.0,123290000.0,176260000.0,,125430000.0,99765000.0,19069000.0,,3407500000.0,,642300000.0,55773000.0,,,28994000.0,151860000.0,,1066800000.0,133300000.0,11477000.0,2302700000.0,202860000.0,95056000.0,133920000.0,,,73293000.0,45697000.0,99981000.0,151890000.0,23534000.0,89442000.0,,39750000.0,119280000.0,,45901000.0,186630000.0,23543000.0,61948000.0,46133000.0,4981900000.0,1357300000.0,867130000.0,,13738000.0,4214900000.0,,176850000.0,35347000.0,36035000.0,236420000.0,187370000.0,,,126790000.0,84625000.0,,230400000.0,785050000.0,102960000.0,587430000.0,667780000.0,98577000.0,1696200000.0,148400000.0,19318000.0,,847560000.0,27711000.0,402440000.0,112590000.0,63925000.0,134790000.0,101780000.0,32324000.0,,80741000.0,,34809000.0,,,,77274000.0,2531000000.0,,,162330000.0,10847000.0,19522000.0,,296770000.0,,78497000.0,54029000.0,619090000.0,393900000.0,105030000.0,190240000.0,547080000.0,217580000.0,1696200000.0,,345940000.0,77764000.0,,103520000.0,286140000.0,143430000.0,223490000.0,460410000.0,97341000.0,7079000.0,,,,32392000.0,688000000.0,71685000.0,416460000.0,,41625000.0,118060000.0,197110000.0,514580000.0,,2747500000.0,77397000.0,3675600000.0,1579100000.0,43782000.0,246660000.0,162290000.0,,1376700000.0,16447000.0,22706000.0,1952100000.0,639360000.0,95372000.0,,293020000.0,266570000.0,681040000.0,,8910800000.0,,86411000.0,,82767000.0,,265790000.0,76580000.0,1582700000.0,,202100000.0,617870000.0,,1559200000.0,1116400000.0,31010000.0,121950000.0,820530000.0,63901000.0,,10486000000.0,247200000.0,11794000.0,,,,,679430000.0,248980000.0,136870000.0,,,52239000.0,296570000.0,27587000.0,54200000.0,104990000.0,37202000.0,683450000.0,65906000.0,367650000.0,,380980000.0,8372400000.0,718490000.0,9445700000.0,37307000.0,170240000.0,18889000.0,20468000.0,300950000.0,49774000.0,578590000.0,3715000000.0,60033000.0,127780000.0,304580000.0,,,2685400000.0,1482000000.0,,62481000.0,93776000.0,303900000.0,3432000000.0,420100000.0,444750000.0,16192000000.0,5427800000.0,453310000.0,159580000.0,3152700000.0,1358700000.0,121030000.0,35764000.0,131880000.0,156990000.0,2305900000.0,432330000.0,482370000.0,43066000.0,,86293000.0,406390000.0,530620000.0,295110000.0,7799200.0,14762000000.0,21721000.0,587010000.0,8834700000.0,,2636200000.0,14355000.0,,1797900000.0,14876000.0,89476000.0,512530000.0,102420000.0,164530000.0,,6872300000.0,182030000.0,21381000.0,24774000.0,,122420000.0,244700000.0,127080000.0,,31977000.0,271740000.0,5239500000.0,363320000.0,534860000.0,1619000000.0,514610000.0,4536200000.0,,45655000.0,35976000.0,189700000.0,,18261000.0,560540000.0,,141780000.0,337070000.0,155320000.0,9868600000.0,812420000.0,17314000.0,,970470000.0,7940700000.0,,825600000.0,281450000.0,742940000.0,250730000.0,1372200000.0,205150000.0,168370000.0,1667200000.0,1383100000.0,,188950000.0,337910000.0,180080000.0,2200400000.0,,,140390000.0,19930000.0,63526000.0,171170000.0,,1753200000.0,64440000.0,478730000.0,777760000.0,1416500000.0,1082800000.0,461270000.0,,248020000.0,234560000.0,116760000.0,160550000.0,171830000.0,,200350000.0,,456490000.0,9093700.0,,371540000.0,355270000.0,660440000.0,1257000000.0,10190000000.0,284290000.0,,70695000.0,3820000000.0,,22272000.0,133810000.0,54372000.0,67146000.0,94044000.0,23693000.0,193800000.0,317720000.0,690440000.0,12891000.0,352490000.0,317350000.0,308550000.0,1245100000.0,158840000.0,37577000.0,1628000000.0,42496000.0,92446000.0,94608000.0,266720000.0,,5687200000.0,599260000.0,,,,15850000.0,,15120000.0,,284370000.0,3031100000.0,,,459310000.0,248860000.0,87344000.0,1480300000.0,201540000.0,3689900000.0,199630000.0,8510000000.0,70664000.0,566900000.0,461440000.0,9539800.0,697660000.0,106090000.0,134640000.0,9434300.0,7405100000.0,,1991600000.0,392400000.0,52280000.0,,,,,,137020000.0 +2019_12_20_14_15_Q-Exactive-HF-X-Orbitrap_6070,,,37574000000.0,219620000.0,,10807000.0,,1179000000.0,603980000.0,73130000.0,24540000.0,,145590000.0,1582800000.0,122650000.0,74671000.0,,525480000.0,,124150000.0,2832500000.0,81121000.0,244290000.0,2451900000.0,468920000.0,1932700000.0,84573000.0,972450000.0,209560000.0,49938000.0,49279000.0,74214000.0,6663200000.0,,,156290000.0,33997000000.0,128720000.0,5264100000.0,160950000.0,702570000.0,48997000.0,4517400000.0,1454700000.0,582730000.0,2103900000.0,152270000.0,184420000.0,1012500000.0,279930000.0,77059000.0,31324000.0,1122300000.0,445060000.0,50622000.0,30115000.0,41793000.0,421740000.0,506880000.0,5328600000.0,71763000.0,213570000.0,41180000.0,204090000.0,,34521000.0,,5097700000.0,,1082100000.0,198790000.0,,35980000.0,230410000.0,271080000.0,8859000.0,1512500000.0,171590000.0,90496000.0,3804900000.0,283850000.0,230250000.0,356550000.0,,,110360000.0,54701000.0,234170000.0,231560000.0,,35889000.0,18390000.0,83811000.0,255540000.0,44427000.0,87004000.0,779570000.0,35246000.0,276240000.0,89094000.0,5389900000.0,2248600000.0,1387100000.0,,36440000.0,6548300000.0,,338610000.0,7773200.0,12266000.0,433850000.0,407780000.0,,,,67643000.0,,522220000.0,972350000.0,355330000.0,914720000.0,838830000.0,121520000.0,3237000000.0,152250000.0,125570000.0,47388000.0,1021800000.0,17757000.0,793530000.0,,71424000.0,193550000.0,246510000.0,51000000.0,27745000.0,165910000.0,,133970000.0,,13868000.0,,77832000.0,4100800000.0,9012900.0,13763000.0,315170000.0,16503000.0,50727000.0,14572000.0,589340000.0,,122450000.0,108520000.0,860430000.0,718650000.0,418350000.0,218530000.0,1208200000.0,428640000.0,2513400000.0,,533030000.0,60865000.0,46728000.0,198540000.0,379330000.0,201260000.0,305710000.0,646590000.0,173370000.0,,148650000.0,38752000.0,66071000.0,53245000.0,942820000.0,118000000.0,915220000.0,,136230000.0,251260000.0,83201000.0,880190000.0,85969000.0,3814800000.0,128720000.0,4705400000.0,2303300000.0,67089000.0,338660000.0,355480000.0,,2016300000.0,28031000.0,18209000.0,2098000000.0,1018000000.0,658910000.0,625610000.0,215430000.0,541580000.0,1575600000.0,26923000.0,1749200000.0,27711000.0,183440000.0,93874000.0,114370000.0,,303660000.0,13625000.0,2181000000.0,,356670000.0,556150000.0,,2327600000.0,1689600000.0,68125000.0,115180000.0,1789700000.0,88722000.0,44243000.0,18268000000.0,110780000.0,24125000.0,21149000.0,,,,805400000.0,309370000.0,259910000.0,,,143010000.0,349620000.0,112020000.0,141000000.0,194990000.0,57279000.0,1585900000.0,132680000.0,436110000.0,,382120000.0,13261000000.0,1550000000.0,14782000000.0,264130000.0,268360000.0,,72947000.0,419760000.0,125000000.0,758300000.0,4840100000.0,54401000.0,66289000.0,661580000.0,,,5118800000.0,2613900000.0,,53745000.0,119670000.0,408010000.0,5250700000.0,642060000.0,486820000.0,20813000000.0,8103700000.0,777100000.0,295630000.0,4491700000.0,1762600000.0,1224300000.0,34370000.0,371130000.0,165410000.0,3846300000.0,301750000.0,784970000.0,68408000.0,28924000.0,110290000.0,439780000.0,1390200000.0,745630000.0,29188000.0,16046000000.0,42397000.0,930310000.0,11328000000.0,22229000.0,2293900000.0,121170000.0,,2724000000.0,35097000.0,75716000.0,938990000.0,138130000.0,540280000.0,,,415350000.0,,30786000.0,60269000.0,287780000.0,348150000.0,410340000.0,17363000.0,99146000.0,445470000.0,9791500000.0,503330000.0,779930000.0,2499900000.0,1036000000.0,7051000000.0,1216600000.0,173870000.0,117710000.0,456430000.0,,32859000.0,944410000.0,,191650000.0,439940000.0,174350000.0,16764000000.0,1426100000.0,,69261000.0,2512200000.0,12612000000.0,,959830000.0,536660000.0,926200000.0,282360000.0,1977700000.0,517460000.0,168570000.0,2556900000.0,1562400000.0,,366430000.0,732170000.0,530800000.0,3741600000.0,,31122000.0,263250000.0,58119000.0,119080000.0,292960000.0,,2456200000.0,41320000.0,425080000.0,1475400000.0,3172000000.0,2472300000.0,352800000.0,,675270000.0,284980000.0,242630000.0,307500000.0,212170000.0,,178810000.0,,1062500000.0,14035000.0,,510730000.0,136820000.0,,1572500000.0,14699000000.0,494780000.0,31168000.0,186920000.0,5294600000.0,,62688000.0,303420000.0,63097000.0,237380000.0,152930000.0,54094000.0,472570000.0,567090000.0,1019400000.0,122900000.0,620220000.0,530330000.0,747080000.0,2035400000.0,267760000.0,49334000.0,2746800000.0,51894000.0,171330000.0,,496100000.0,,7954500000.0,764090000.0,,25302000.0,,21088000.0,16363000.0,114730000.0,,387930000.0,5293900000.0,32998000.0,,931610000.0,465970000.0,107530000.0,2521600000.0,167390000.0,6625100000.0,230410000.0,12939000000.0,108320000.0,1032800000.0,646510000.0,12506000.0,863670000.0,51787000.0,71959000.0,152210000.0,9460400000.0,48333000.0,3229400000.0,382560000.0,169700000.0,,428090000.0,,,,202130000.0 +2019_12_27_12_29_Q-Exactive-HF-X-Orbitrap_6070,,,21600000000.0,168920000.0,,10708000.0,,675300000.0,358290000.0,,8862700.0,,68743000.0,943780000.0,25976000.0,10056000.0,,263320000.0,,29444000.0,1380000000.0,30511000.0,,1126200000.0,240850000.0,848490000.0,57977000.0,623480000.0,144550000.0,23748000.0,5922200.0,98885000.0,3489500000.0,,9441700.0,44792000.0,20047000000.0,49293000.0,3041200000.0,78455000.0,309300000.0,11667000.0,1998800000.0,782460000.0,316010000.0,967410000.0,64362000.0,86046000.0,590300000.0,58481000.0,51405000.0,,552190000.0,373360000.0,14755000.0,,13007000.0,333050000.0,321800000.0,3295500000.0,81163000.0,155400000.0,,151510000.0,89858000.0,31072000.0,,2632400000.0,,466150000.0,58425000.0,,15024000.0,68988000.0,144240000.0,,1084100000.0,78558000.0,54295000.0,2379900000.0,210500000.0,91463000.0,172070000.0,,,66783000.0,,140350000.0,157770000.0,18584000.0,34422000.0,,12348000.0,46083000.0,,,442470000.0,10714000.0,131870000.0,44599000.0,3724100000.0,1393900000.0,688330000.0,,13825000.0,3769800000.0,,314410000.0,,,241180000.0,194700000.0,,,,58621000.0,,232290000.0,818560000.0,170920000.0,537560000.0,456940000.0,59202000.0,1535200000.0,53567000.0,11390000.0,27278000.0,504440000.0,16527000.0,356480000.0,43036000.0,43108000.0,135270000.0,83542000.0,26158000.0,11542000.0,83713000.0,,,,13414000.0,,61298000.0,2371400000.0,27313000.0,,124490000.0,,,,259180000.0,,92193000.0,58719000.0,453420000.0,624270000.0,247750000.0,181780000.0,630530000.0,282030000.0,1406000000.0,,389790000.0,43342000.0,64743000.0,107000000.0,209980000.0,136570000.0,137280000.0,398060000.0,137890000.0,30806000.0,,,17893000.0,,641600000.0,66951000.0,244950000.0,,69863000.0,128010000.0,86941000.0,503040000.0,47677000.0,2300300000.0,63519000.0,2784500000.0,1091500000.0,33949000.0,215410000.0,167690000.0,,813320000.0,,22141000.0,1495600000.0,540160000.0,236600000.0,,101510000.0,231990000.0,802540000.0,,10325000000.0,,115890000.0,96874000.0,48342000.0,,138600000.0,8902600.0,1831700000.0,,177540000.0,449560000.0,,1242000000.0,795100000.0,,68873000.0,1050400000.0,94638000.0,,9701600000.0,226660000.0,12666000.0,,,,,439070000.0,149630000.0,112900000.0,651280000.0,,49724000.0,282220000.0,16495000.0,71429000.0,60389000.0,,757530000.0,50587000.0,220380000.0,,142650000.0,6755100000.0,768020000.0,8230100000.0,103280000.0,190650000.0,18541000.0,81463000.0,280770000.0,46626000.0,426580000.0,3143400000.0,61513000.0,105450000.0,302620000.0,,,2830200000.0,1241200000.0,10373000.0,40832000.0,69435000.0,357630000.0,3212400000.0,321370000.0,220490000.0,12557000000.0,4138200000.0,458810000.0,185400000.0,2573200000.0,863600000.0,107300000.0,,183460000.0,104160000.0,2097900000.0,279690000.0,415480000.0,33269000.0,5847600.0,23208000.0,381540000.0,803870000.0,264290000.0,9206800.0,6841400000.0,33659000.0,388860000.0,6724000000.0,,1979400000.0,17333000.0,,1335900000.0,,13313000.0,242470000.0,,207440000.0,,,185100000.0,,18919000.0,19374000.0,134080000.0,201670000.0,91558000.0,28168000.0,42346000.0,210860000.0,4927100000.0,249410000.0,334080000.0,1551900000.0,580940000.0,4450700000.0,886350000.0,99259000.0,44684000.0,41819000.0,,19693000.0,10538000.0,,130050000.0,234440000.0,,10849000000.0,643450000.0,15507000.0,28972000.0,1237500000.0,16151000000.0,,618090000.0,175970000.0,640880000.0,320570000.0,1481600000.0,253170000.0,35090000.0,1070800000.0,958340000.0,,186540000.0,311210000.0,202240000.0,1416000000.0,,,144620000.0,22096000.0,55356000.0,154720000.0,,1419900000.0,44040000.0,214030000.0,612080000.0,1768300000.0,1180300000.0,610080000.0,,387920000.0,146020000.0,59719000.0,101950000.0,110330000.0,,72346000.0,,508750000.0,7963300.0,,360410000.0,65397000.0,,1158100000.0,8589500000.0,222520000.0,,83135000.0,3691000000.0,,,177840000.0,54776000.0,101290000.0,53776000.0,45304000.0,168390000.0,391710000.0,666790000.0,15823000.0,295570000.0,181140000.0,413050000.0,1163700000.0,150620000.0,16500000.0,1666400000.0,50429000.0,148700000.0,80814000.0,268680000.0,,4496600000.0,387890000.0,,,,,,38959000.0,13805000.0,134190000.0,2946800000.0,,87427000.0,525470000.0,268450000.0,63110000.0,1480100000.0,144000000.0,3797400000.0,111440000.0,7118100000.0,47609000.0,549010000.0,398760000.0,17239000.0,556740000.0,65526000.0,56141000.0,49162000.0,5774200000.0,67555000.0,1466200000.0,168170000.0,67976000.0,,,,,,90780000.0 +2019_12_29_15_06_Q-Exactive-HF-X-Orbitrap_6070,83858000.0,,60643000000.0,249130000.0,41863000.0,,44597000.0,1600200000.0,1155800000.0,,17399000.0,,64304000.0,1994100000.0,190650000.0,57645000.0,27482000.0,384310000.0,159830000.0,33560000.0,5161700000.0,210570000.0,338740000.0,1708700000.0,99922000.0,1986600000.0,12935000.0,1169200000.0,46625000.0,312490000.0,620830000.0,131330000.0,8924000000.0,280740000.0,310820000.0,195480000.0,39300000000.0,82297000.0,4211900000.0,489920000.0,43720000.0,208860000.0,3742200000.0,1563300000.0,551490000.0,2127000000.0,77220000.0,142560000.0,,57675000.0,150470000.0,,539760000.0,1411800000.0,,,94465000.0,666690000.0,165960000.0,6026600000.0,115890000.0,291240000.0,157320000.0,465730000.0,280330000.0,416120000.0,23030000.0,4663700000.0,616640000.0,1028600000.0,,30731000.0,35123000.0,71783000.0,64618000.0,165200000.0,149600000.0,156520000.0,21390000.0,4884700000.0,435520000.0,44620000.0,34336000.0,,110030000.0,54551000.0,38415000.0,20404000.0,52016000.0,56561000.0,111970000.0,68780000.0,,90738000.0,68940000.0,234490000.0,239360000.0,66361000.0,480330000.0,160610000.0,5838300000.0,1896800000.0,1202900000.0,210080000.0,116670000.0,6658900000.0,,291810000.0,,126540000.0,3952700000.0,869250000.0,94459000.0,93881000.0,119250000.0,218660000.0,,1384600000.0,2201400000.0,501050000.0,2059800000.0,180950000.0,279570000.0,3683100000.0,40325000.0,35605000.0,,1064100000.0,43005000.0,967240000.0,161000000.0,,317510000.0,,30016000.0,103900000.0,185450000.0,27218000000.0,546500000.0,52989000.0,32034000.0,253240000.0,69481000.0,4269700000.0,6558300.0,,313200000.0,111370000.0,303120000.0,28303000.0,823170000.0,,267330000.0,587630000.0,1070500000.0,886770000.0,515940000.0,46449000.0,1644100000.0,189060000.0,4102800000.0,,486070000.0,119720000.0,20176000.0,232430000.0,152220000.0,422700000.0,409530000.0,210980000.0,1004900000.0,1006000000.0,,,79489000.0,76479000.0,2204500000.0,309670000.0,1473700000.0,422940000.0,208200000.0,112150000.0,117780000.0,545540000.0,35629000.0,3231200000.0,114620000.0,4862700000.0,2705100000.0,282820000.0,380640000.0,233600000.0,69059000.0,1801600000.0,68354000.0,33454000.0,1592100000.0,1220400000.0,1827000000.0,,758760000.0,300050000.0,2954100000.0,27283000.0,4798600000.0,,175540000.0,148710000.0,113180000.0,,112700000.0,30303000.0,3452500000.0,329230000.0,67030000.0,716300000.0,2118400000.0,2579900000.0,2544800000.0,,222380000.0,1110200000.0,59416000.0,87502000.0,55180000000.0,64635000.0,60879000.0,45996000.0,,,135270000.0,1104800000.0,381190000.0,,,640690000.0,,495300000.0,31438000.0,63124000.0,19262000.0,43170000.0,695700000.0,408940000.0,1539000000.0,616270000.0,477770000.0,17735000000.0,725280000.0,12209000000.0,104140000.0,,51937000.0,111140000.0,196360000.0,155960000.0,1173600000.0,14208000000.0,,270520000.0,720450000.0,,,4719000000.0,1635800000.0,53417000.0,52976000.0,143510000.0,93723000.0,6285200000.0,408500000.0,711970000.0,54883000000.0,8959000000.0,268580000.0,57835000.0,5272500000.0,2125400000.0,415410000.0,,742960000.0,370270000.0,3728900000.0,577480000.0,217540000.0,,38063000.0,199890000.0,2742900000.0,318760000.0,799180000.0,17391000.0,18228000000.0,47473000.0,194560000.0,5586800000.0,,2374300000.0,,179370000.0,3930100000.0,12987000.0,66535000.0,715920000.0,204580000.0,400870000.0,20021000.0,,349060000.0,,,89850000.0,312720000.0,132570000.0,226990000.0,,414430000.0,343430000.0,6719800000.0,553940000.0,,3516000000.0,2268900000.0,11338000000.0,23303000000.0,36682000.0,144750000.0,60922000.0,84881000.0,328320000.0,849540000.0,126540000.0,292340000.0,333100000.0,96217000.0,14918000000.0,852200000.0,36018000.0,,3225200000.0,7944700000.0,,313650000.0,890270000.0,1302800000.0,1098000000.0,1422900000.0,772560000.0,132860000.0,9482900000.0,2727600000.0,209190000.0,103080000.0,446240000.0,2085000000.0,6376700000.0,,304790000.0,72813000.0,52122000.0,302630000.0,526370000.0,47869000.0,3343400000.0,158590000.0,90708000.0,4714700000.0,2081400000.0,310720000.0,206870000.0,331460000.0,6015000000.0,1139500000.0,33945000.0,,347770000.0,69281000.0,236040000.0,309830000.0,757810000.0,,74815000.0,,399820000.0,,4602100000.0,9551500000.0,667030000.0,16258000.0,139830000.0,9081200000.0,68782000.0,172340000.0,173640000.0,126030000.0,,78253000.0,203620000.0,156210000.0,843210000.0,505040000.0,118280000.0,611860000.0,540720000.0,1098600000.0,1345000000.0,114010000.0,36388000.0,1351600000.0,323820000.0,206560000.0,243410000.0,295620000.0,,15200000000.0,516030000.0,76403000.0,,103560000.0,166150000.0,1215600000.0,,74841000.0,197650000.0,8346700000.0,,271280000.0,360200000.0,353820000.0,,1351500000.0,156490000.0,12912000000.0,542900000.0,11527000000.0,,1075400000.0,771910000.0,161680000.0,7088500000.0,60722000.0,81898000.0,396440000.0,6842700000.0,22252000.0,2376300000.0,1198300000.0,297470000.0,34130000.0,536240000.0,218600000.0,18987000.0,79412000.0,214250000.0 +2019_12_29_18_18_Q-Exactive-HF-X-Orbitrap_6070,192680000.0,,63093000000.0,214030000.0,100020000.0,7181400.0,69400000.0,2347900000.0,1239100000.0,25611000.0,45509000.0,28360000.0,90707000.0,2150700000.0,138250000.0,,5683800.0,602040000.0,141810000.0,57163000.0,5637800000.0,160630000.0,400490000.0,2342500000.0,256450000.0,2348300000.0,,1416300000.0,58032000.0,419460000.0,511470000.0,45902000.0,10202000000.0,348320000.0,482220000.0,308740000.0,48391000000.0,127290000.0,5977600000.0,458820000.0,41246000.0,175410000.0,3580200000.0,3274100000.0,746940000.0,2063300000.0,,154030000.0,,98614000.0,237230000.0,,674410000.0,1805100000.0,,48800000.0,159050000.0,728070000.0,158580000.0,7651800000.0,193510000.0,282480000.0,188360000.0,546800000.0,421830000.0,319140000.0,76270000.0,5353800000.0,749460000.0,1245500000.0,,62701000.0,36333000.0,141220000.0,101910000.0,24887000.0,464480000.0,78234000.0,,5284900000.0,438370000.0,62093000.0,120010000.0,,173150000.0,50112000.0,29309000.0,,66103000.0,56385000.0,85957000.0,,,136560000.0,89191000.0,315010000.0,231770000.0,73773000.0,596680000.0,113600000.0,6437000000.0,2767000000.0,1656700000.0,257120000.0,68449000.0,5280700000.0,,275110000.0,57954000.0,145310000.0,6861300000.0,1089300000.0,74135000.0,165970000.0,1164300000.0,336330000.0,,1404800000.0,2551500000.0,528620000.0,2526800000.0,335020000.0,304380000.0,4429800000.0,,40021000.0,61579000.0,1339400000.0,,1174400000.0,169530000.0,22201000.0,291790000.0,42341000.0,,312590000.0,189830000.0,,503330000.0,47709000.0,,314670000.0,105110000.0,5367700000.0,8410600.0,20042000.0,269240000.0,148380000.0,193600000.0,20802000.0,856380000.0,,266730000.0,781530000.0,1258300000.0,1346200000.0,698660000.0,62171000.0,2690500000.0,158760000.0,5333900000.0,15676000.0,628580000.0,161430000.0,,,128480000.0,518230000.0,555780000.0,419380000.0,859960000.0,843550000.0,,,45339000.0,67151000.0,2701700000.0,298560000.0,1666900000.0,360890000.0,222810000.0,170400000.0,138140000.0,636560000.0,,3675200000.0,228100000.0,6546300000.0,2484800000.0,498080000.0,479020000.0,345100000.0,57636000.0,2177300000.0,78302000.0,148070000.0,2228200000.0,1144300000.0,1873400000.0,,886240000.0,374330000.0,3624800000.0,17544000.0,20140000000.0,,281020000.0,364530000.0,177540000.0,,233050000.0,38201000.0,4895400000.0,318750000.0,117710000.0,1075200000.0,2812900000.0,2775700000.0,2926600000.0,98952000.0,360530000.0,1250200000.0,42191000.0,112400000.0,63651000000.0,,37824000.0,68847000.0,,,215820000.0,1098800000.0,393310000.0,,,706860000.0,33344000.0,638190000.0,44046000.0,82112000.0,35924000.0,38417000.0,1026400000.0,564620000.0,1274000000.0,887690000.0,608700000.0,20076000000.0,1057200000.0,16199000000.0,190040000.0,48826000.0,40930000.0,155920000.0,321750000.0,188570000.0,1443800000.0,16611000000.0,,203820000.0,1080000000.0,,94036000.0,5643000000.0,2138500000.0,15651000.0,122500000.0,189080000.0,139940000.0,8245700000.0,481220000.0,767030000.0,69083000000.0,9510600000.0,479400000.0,133300000.0,7666700000.0,3185800000.0,414840000.0,,896470000.0,368050000.0,4726400000.0,690930000.0,190160000.0,62727000.0,21713000.0,274230000.0,2964300000.0,349130000.0,1417000000.0,9763300.0,20441000000.0,34310000.0,344900000.0,7656100000.0,68892000.0,2302600000.0,,1976400000.0,4246600000.0,14699000.0,62976000.0,1161900000.0,211920000.0,322820000.0,45375000.0,,376830000.0,52454000.0,,160340000.0,298190000.0,148780000.0,159570000.0,77795000.0,660920000.0,455180000.0,6521200000.0,897640000.0,,3531700000.0,1884100000.0,15211000000.0,24464000000.0,73820000.0,274340000.0,128630000.0,251540000.0,517590000.0,941450000.0,54838000.0,321060000.0,545800000.0,126710000.0,18197000000.0,997160000.0,,,3924100000.0,10718000000.0,1514200000.0,3060100000.0,1174200000.0,1363700000.0,1030500000.0,1688100000.0,964870000.0,184320000.0,11080000000.0,2301400000.0,349260000.0,74333000.0,530120000.0,2013300000.0,7287100000.0,,2723800000.0,50487000.0,99353000.0,279320000.0,462780000.0,,3898700000.0,191910000.0,173900000.0,5041800000.0,2718400000.0,699180000.0,365120000.0,412030000.0,6644300000.0,1351600000.0,179610000.0,,399010000.0,29575000.0,243100000.0,,832420000.0,,86780000.0,323010000.0,596330000.0,120100000.0,5827600000.0,8083700000.0,1135000000.0,,150480000.0,12378000000.0,152490000.0,261370000.0,217870000.0,188090000.0,,232230000.0,177610000.0,179030000.0,799360000.0,590080000.0,120990000.0,702500000.0,549110000.0,1217600000.0,1541600000.0,82087000.0,33247000.0,1681800000.0,378290000.0,305610000.0,306690000.0,385540000.0,,19517000000.0,708300000.0,,19015000.0,172350000.0,148560000.0,1695200000.0,,112200000.0,1431900000.0,9741600000.0,25694000.0,322950000.0,312940000.0,481420000.0,,1296500000.0,129360000.0,16093000000.0,217550000.0,12221000000.0,16413000.0,737510000.0,869300000.0,200290000.0,7220300000.0,90607000.0,195480000.0,437920000.0,8758600000.0,,3166500000.0,1453400000.0,480780000.0,,705720000.0,337660000.0,27467000.0,25029000.0,315990000.0 +2020_01_02_17_38_Q-Exactive-HF-X-Orbitrap_6070,45563000.0,,29261000000.0,,,4992300.0,77811000.0,537050000.0,349750000.0,,,,,304870000.0,,,18553000.0,58003000.0,,,1317200000.0,27618000.0,166870000.0,497300000.0,43407000.0,356540000.0,,388030000.0,26457000.0,39762000.0,165530000.0,,2439000000.0,74539000.0,57140000.0,52565000.0,16596000000.0,6814300.0,1807900000.0,,16153000.0,17149000.0,1477600000.0,321310000.0,119860000.0,522490000.0,11885000.0,,,,29358000.0,220840000.0,107370000.0,363870000.0,,,,118180000.0,31867000.0,1403700000.0,,,,71133000.0,98515000.0,79002000.0,,1418200000.0,179370000.0,225460000.0,,,,38533000.0,20058000.0,19411000.0,107580000.0,6265300.0,,1452500000.0,94667000.0,,12738000.0,,23890000.0,9298400.0,,79838000.0,173040000.0,9142800.0,,,,,29127000.0,53634000.0,74455000.0,,44962000.0,58698000.0,1669500000.0,640420000.0,185770000.0,63460000.0,,2684000000.0,,189800000.0,,9237300.0,1186800000.0,196610000.0,,,,84029000.0,,458360000.0,695500000.0,128180000.0,216980000.0,60205000.0,41033000.0,915150000.0,,,85210000.0,352910000.0,,301670000.0,,,28346000.0,,,17257000.0,56695000.0,2469400000.0,221500000.0,9500300.0,,39310000.0,,766340000.0,,,70703000.0,,,12020000.0,34371000.0,37820000.0,,256940000.0,366940000.0,219160000.0,97595000.0,,950860000.0,93382000.0,1939200000.0,,79331000.0,,,,41724000.0,14640000.0,35559000.0,67653000.0,136310000.0,347480000.0,,,34551000.0,,292370000.0,73496000.0,227660000.0,41728000.0,43804000.0,,9340700.0,86709000.0,,955020000.0,59094000.0,1218500000.0,840840000.0,49290000.0,56271000.0,49448000.0,,764210000.0,,,526420000.0,174990000.0,348230000.0,,69275000.0,24730000.0,1428300000.0,,8088000000.0,14969000.0,34492000.0,91608000.0,46003000.0,,,,1733600000.0,,25667000.0,216600000.0,738280000.0,1169800000.0,680370000.0,,54399000.0,229900000.0,,39916000.0,26820000000.0,21924000.0,,,,,15295000.0,286030000.0,23702000.0,,,96236000.0,,299220000.0,,,,,92451000.0,65397000.0,194860000.0,20007000.0,80974000.0,8048700000.0,112020000.0,4535000000.0,,,,24911000.0,36132000.0,16005000.0,305290000.0,6355100000.0,,47385000.0,108870000.0,,13598000.0,1773400000.0,393890000.0,25780000.0,,25055000.0,21877000.0,2147700000.0,140290000.0,126100000.0,19185000000.0,2192800000.0,27906000.0,,1826900000.0,879980000.0,615450000.0,,208850000.0,97490000.0,1119000000.0,179910000.0,64022000.0,,,23119000.0,733950000.0,247120000.0,297220000.0,5454000.0,7058700000.0,,70761000.0,1685600000.0,39383000.0,626920000.0,,,1488300000.0,22722000.0,,139500000.0,123300000.0,,,,31123000.0,,,,95904000.0,,2080200000.0,,82841000.0,163580000.0,4421000000.0,145010000.0,,795330000.0,698200000.0,4410000000.0,3534200000.0,,36713000.0,,,69099000.0,,,107090000.0,103260000.0,,5557200000.0,303080000.0,,,1286800000.0,2822300000.0,,2272200000.0,214870000.0,301150000.0,646950000.0,447210000.0,104410000.0,42545000.0,3004500000.0,518510000.0,47769000.0,,84834000.0,530390000.0,1965300000.0,,132340000.0,,,,221290000.0,,960350000.0,,,1125000000.0,975770000.0,169610000.0,,52421000.0,1708400000.0,230220000.0,30987000.0,,54570000.0,,9584000.0,,196650000.0,,,,238870000.0,,814410000.0,4953100000.0,100400000.0,,59617000.0,4585500000.0,,53211000.0,30099000.0,20471000.0,,34614000.0,17055000.0,,240930000.0,136820000.0,,149690000.0,47505000.0,246280000.0,319350000.0,76962000.0,21122000.0,253010000.0,135460000.0,22358000.0,76376000.0,71839000.0,,10900000000.0,32649000.0,,,,21875000.0,198620000.0,2849600.0,,19402000.0,2926600000.0,,,50457000.0,80396000.0,,268020000.0,,7323500000.0,,2975000000.0,,230860000.0,173820000.0,10624000.0,3215300000.0,,,118850000.0,1671400000.0,,499520000.0,222610000.0,22562000.0,,136330000.0,,,,37093000.0 +2020_01_03_11_17_Q-Exactive-HF-X-Orbitrap_6070,,,60145000000.0,78036000.0,17016000.0,,98240000.0,975200000.0,366580000.0,,,,,259370000.0,,,,215110000.0,,15799000.0,2341900000.0,65552000.0,,398210000.0,27977000.0,1285200000.0,,1177200000.0,48616000.0,19118000.0,484130000.0,19338000.0,3656100000.0,113960000.0,50377000.0,109970000.0,28186000000.0,,2594300000.0,185160000.0,,6099200.0,2395500000.0,1276400000.0,160030000.0,1078200000.0,,,,,,374860000.0,41609000.0,358580000.0,,,43192000.0,49211000.0,40832000.0,2577100000.0,69225000.0,,,36746000.0,,,31846000.0,2288800000.0,141330000.0,569220000.0,,,14305000.0,30770000.0,46158000.0,,44799000.0,59479000.0,,2121400000.0,137520000.0,75475000.0,12028000.0,,137640000.0,,,44594000.0,223650000.0,,,,,19197000.0,,64971000.0,125410000.0,,461030000.0,,3270300000.0,1187600000.0,703710000.0,53912000.0,33944000.0,3523600000.0,,,,,1919100000.0,355390000.0,28727000.0,,,60065000.0,,299010000.0,616870000.0,140540000.0,317270000.0,175400000.0,91736000.0,1483200000.0,,31695000.0,199050000.0,491010000.0,,240650000.0,25852000.0,,118510000.0,27793000.0,,6427100.0,76659000.0,11681000000.0,99603000.0,,,76009000.0,31417000.0,1879900000.0,,,,36794000.0,113670000.0,,118590000.0,69269000.0,52201000.0,273760000.0,1273300000.0,592080000.0,179580000.0,,1567200000.0,209040000.0,1681000000.0,,277600000.0,,,203150000.0,184480000.0,84877000.0,49505000.0,35450000.0,369600000.0,526130000.0,32562000.0,,,50841000.0,1765200000.0,46906000.0,656650000.0,51096000.0,131060000.0,,80016000.0,81020000.0,24092000.0,1625300000.0,74183000.0,2003200000.0,1141600000.0,91345000.0,99536000.0,61578000.0,,1051900000.0,,15904000.0,1250300000.0,561330000.0,738840000.0,,,91620000.0,3200400000.0,,3335900000.0,,29777000.0,273900000.0,18249000.0,,18489000.0,,2959200000.0,,34592000.0,510800000.0,,4011300000.0,1478100000.0,,60996000.0,239930000.0,,,36117000000.0,,,,,,,321010000.0,27888000.0,,,439650000.0,,173210000.0,,,,,273310000.0,119400000.0,379220000.0,53340000.0,112600000.0,15202000000.0,98898000.0,9889700000.0,,,,43901000.0,56489000.0,85224000.0,409180000.0,7145700000.0,,31401000.0,436580000.0,,45660000.0,2784400000.0,476380000.0,,,147800000.0,,3252000000.0,30768000.0,151590000.0,53435000000.0,7198000000.0,47111000.0,,2990000000.0,1140500000.0,112430000.0,,223450000.0,108610000.0,2454200000.0,155580000.0,104240000.0,,,59229000.0,1406300000.0,549540000.0,310760000.0,,10630000000.0,,187650000.0,3359000000.0,105300000.0,1460200000.0,,990630000.0,1917500000.0,,,413510000.0,,130530000.0,778250000.0,8881600000.0,87496000.0,,,,132950000.0,13835000.0,21183000.0,,144490000.0,,5073000000.0,213610000.0,,1235200000.0,1547300000.0,4767100000.0,8635000000.0,,97610000.0,98975000.0,10705000.0,175170000.0,,,157500000.0,122100000.0,30155000.0,13830000000.0,776490000.0,,,1058400000.0,5070000000.0,,4839100000.0,870290000.0,527050000.0,973720000.0,485190000.0,774130000.0,149370000.0,4697300000.0,1093300000.0,60895000.0,19853000.0,347500000.0,1419100000.0,4302500000.0,,99794000.0,,15154000.0,,26014000.0,,2823000000.0,,,2718300000.0,2194500000.0,392890000.0,,56533000.0,3766100000.0,938830000.0,84676000.0,,,,2083900.0,,201730000.0,,45849000.0,230690000.0,326430000.0,,3654300000.0,6343700000.0,198490000.0,,,7191900000.0,,140690000.0,75596000.0,2009500.0,,113260000.0,,,309370000.0,87504000.0,12107000.0,19985000.0,88747000.0,418370000.0,420620000.0,,,750980000.0,107750000.0,117170000.0,178400000.0,138000000.0,,11549000000.0,252810000.0,,,,39234000.0,330510000.0,,,57102000.0,4716100000.0,,,92681000.0,156940000.0,65807000.0,619210000.0,,7338100000.0,146920000.0,5733700000.0,,319720000.0,378800000.0,32748000.0,2806300000.0,,21262000.0,236660000.0,2924700000.0,,856050000.0,505330000.0,123130000.0,,149130000.0,,,, +2020_01_03_16_58_Q-Exactive-HF-X-Orbitrap_6070,,58359000.0,69862000000.0,,51597000.0,,106030000.0,993940000.0,534070000.0,16621000.0,52447000.0,50300000.0,,1229300000.0,77315000.0,,55923000.0,184990000.0,179860000.0,,4040000000.0,163650000.0,687080000.0,1227900000.0,194270000.0,1352700000.0,28993000.0,1362100000.0,42458000.0,227550000.0,422750000.0,128690000.0,6146700000.0,54763000.0,217020000.0,235430000.0,34776000000.0,32895000.0,3733500000.0,424260000.0,,180280000.0,2526000000.0,2598900000.0,287820000.0,1230000000.0,49530000.0,109190000.0,,39389000.0,68587000.0,,1778800000.0,1037600000.0,,51376000.0,79296000.0,247870000.0,140680000.0,5789900000.0,123650000.0,150960000.0,88163000.0,504830000.0,248170000.0,245200000.0,28720000.0,4438000000.0,256460000.0,1088300000.0,,23701000.0,,83126000.0,103570000.0,,215300000.0,60976000.0,,3161600000.0,290260000.0,22877000.0,41837000.0,43289000.0,203640000.0,31470000.0,,7043500.0,,,,22661000.0,,64448000.0,170100000.0,193680000.0,261670000.0,,228770000.0,41477000.0,3908400000.0,1820400000.0,861110000.0,241240000.0,54631000.0,4564000000.0,,260970000.0,,92366000.0,7962600000.0,724840000.0,45722000.0,70034000.0,88454000.0,97750000.0,,813290000.0,1813500000.0,210540000.0,714330000.0,162530000.0,168490000.0,2314300000.0,17755000.0,58122000.0,86197000.0,825660000.0,,599920000.0,8154400.0,22722000.0,172910000.0,,,103670000.0,215430000.0,,418150000.0,,,225870000.0,117510000.0,3426400000.0,7231000.0,,125270000.0,78851000.0,181290000.0,19134000.0,736580000.0,160330000.0,163550000.0,555310000.0,652190000.0,886450000.0,572110000.0,,1103500000.0,,2986100000.0,,365290000.0,50432000.0,,,112520000.0,451660000.0,299260000.0,165100000.0,443450000.0,738010000.0,24614000.0,,76621000.0,148370000.0,1069400000.0,193680000.0,847700000.0,255560000.0,84325000.0,67987000.0,184960000.0,694620000.0,,1933600000.0,191390000.0,3582600000.0,2071400000.0,200120000.0,268870000.0,135050000.0,59684000.0,1340200000.0,88766000.0,68039000.0,1123200000.0,846750000.0,1263000000.0,,466960000.0,240020000.0,2461500000.0,81424000.0,2876300000.0,18851000.0,220200000.0,204640000.0,29541000.0,,78148000.0,15670000.0,3990000000.0,250710000.0,94678000.0,798550000.0,1915500000.0,2188300000.0,2114200000.0,,124540000.0,1218100000.0,27125000.0,81855000.0,29474000000.0,110620000.0,,69500000.0,,,62587000.0,933290000.0,55606000.0,,,467640000.0,24565000.0,572670000.0,23064000.0,131290000.0,31268000.0,,394810000.0,203870000.0,1153700000.0,555320000.0,236460000.0,21613000000.0,162540000.0,12189000000.0,167040000.0,,,70123000.0,81195000.0,138960000.0,756310000.0,20216000000.0,,212570000.0,401140000.0,,,4480300000.0,1125500000.0,21204000.0,30181000.0,84121000.0,72300000.0,5642200000.0,219310000.0,311710000.0,44059000000.0,7229800000.0,103760000.0,,3885400000.0,1237700000.0,384720000.0,,576380000.0,287900000.0,3339900000.0,289110000.0,227970000.0,50434000.0,,178310000.0,1855200000.0,116640000.0,785940000.0,60946000.0,14252000000.0,,224230000.0,3776800000.0,59419000.0,2132200000.0,,,2441900000.0,45535000.0,71278000.0,686660000.0,263360000.0,292930000.0,1725500000.0,,192530000.0,35702000.0,10439000.0,62914000.0,237280000.0,66811000.0,151370000.0,80578000.0,261210000.0,271880000.0,8849600000.0,387060000.0,,2515700000.0,1488800000.0,11435000000.0,791370000.0,27185000.0,37026000.0,67025000.0,162090000.0,210840000.0,9555600.0,67583000.0,197970000.0,299150000.0,65786000.0,12669000000.0,988510000.0,,,2524400000.0,7009300000.0,,4322200000.0,635550000.0,901930000.0,664270000.0,825920000.0,585650000.0,,5366800000.0,1944800000.0,169560000.0,27865000.0,175990000.0,2074800000.0,5207300000.0,,60642000.0,42698000.0,29463000.0,158640000.0,242380000.0,34472000.0,1570800000.0,176330000.0,98050000.0,4141900000.0,1875800000.0,361820000.0,219810000.0,253350000.0,3758700000.0,1090100000.0,126170000.0,39642000.0,234780000.0,,82299000.0,,418980000.0,,60308000.0,,534880000.0,,2266400000.0,10650000000.0,633600000.0,,135150000.0,8382000000.0,,185480000.0,64093000.0,105100000.0,,149620000.0,,180530000.0,279100000.0,457950000.0,127440000.0,83682000.0,442480000.0,753160000.0,972990000.0,119530000.0,124430000.0,1303500000.0,148250000.0,85636000.0,181720000.0,265650000.0,,14482000000.0,268570000.0,,,57352000.0,60528000.0,659630000.0,20086000.0,70418000.0,199440000.0,6732200000.0,21818000.0,205450000.0,209640000.0,278110000.0,133160000.0,762600000.0,140570000.0,16565000000.0,135500000.0,8381100000.0,,786710000.0,382840000.0,78884000.0,5909600000.0,65319000.0,58625000.0,,4863700000.0,23070000.0,1649200000.0,1763300000.0,233440000.0,69928000.0,,,33041000.0,14512000.0,334330000.0 +2020_01_03_20_10_Q-Exactive-HF-X-Orbitrap_6070,,,68788000000.0,111690000.0,48492000.0,,83047000000.0,1893800000.0,512440000.0,11561000.0,,51662000.0,,1596800000.0,168710000.0,,25261000.0,297280000.0,101680000.0,38070000.0,3840600000.0,61401000.0,424450000.0,1520100000.0,240830000.0,1566500000.0,47300000.0,1581600000.0,60783000.0,34191000.0,353020000.0,124670000.0,5694500000.0,134020000.0,334220000.0,112480000.0,36437000000.0,28900000.0,4311700000.0,350610000.0,,133130000.0,3245800000.0,2688300000.0,405080000.0,1300600000.0,,53442000.0,,13006000.0,18617000.0,670880000.0,435530000.0,1183300000.0,,76917000.0,66280000.0,284930000.0,110980000.0,6675500000.0,35746000.0,113300000.0,123330000.0,454530000.0,,349890000.0,237580000.0,4290500000.0,231980000.0,1397000000.0,312460000.0,52711000.0,11767000.0,126520000.0,100390000.0,17231000.0,449300000.0,39823000.0,,4072200000.0,220780000.0,17941000.0,63419000.0,,234610000.0,,,66571000.0,33625000.0,,,22314000.0,,91316000.0,,216430000.0,267010000.0,,307260000.0,81561000.0,6407900000.0,1643000000.0,1076200000.0,312720000.0,51553000.0,3543800000.0,12052000.0,270910000.0,,113700000.0,4556200000.0,820040000.0,52867000.0,33319000.0,153860000.0,99563000.0,,729090000.0,1915800000.0,441290000.0,476320000.0,129020000.0,266000000.0,1812400000.0,39725000.0,17689000.0,146590000.0,755350000.0,,661830000.0,10807000.0,13560000.0,253400000.0,28026000.0,,60428000.0,145580000.0,,557930000.0,48079000.0,,200870000.0,95464000.0,3989700000.0,,,119670000.0,87164000.0,236000000.0,33088000.0,623860000.0,,182940000.0,358630000.0,636320000.0,921610000.0,490010000.0,,1676700000.0,42195000.0,2672800000.0,83730000.0,320030000.0,40354000.0,,161390000.0,131130000.0,442620000.0,346310000.0,210220000.0,739100000.0,891610000.0,24841000.0,,62705000.0,,2250600000.0,219770000.0,1330100000.0,368520000.0,45921000.0,66352000.0,109940000.0,478370000.0,,2160100000.0,138450000.0,3651300000.0,2662400000.0,144380000.0,178070000.0,149300000.0,26588000.0,1204600000.0,49275000.0,94950000.0,1425400000.0,1260800000.0,1383800000.0,,515100000.0,144210000.0,2943700000.0,61564000.0,2623600000.0,,225840000.0,153520000.0,53474000.0,,74042000.0,12639000.0,3746800000.0,285300000.0,71627000.0,602210000.0,,1586500000.0,2117800000.0,,222210000.0,1321600000.0,36142000.0,95177000.0,31711000000.0,63051000.0,52717000.0,,,,33177000.0,822290000.0,57120000.0,,,273330000.0,60894000.0,487650000.0,,108190000.0,15855000.0,,437710000.0,217470000.0,859800000.0,567460000.0,318880000.0,18802000000.0,424490000.0,10758000000.0,73648000.0,,,75548000.0,81174000.0,144640000.0,692270000.0,19250000000.0,,229020000.0,456810000.0,,39386000.0,3136600000.0,1254700000.0,,1668000000.0,138680000.0,74890000.0,4541900000.0,293520000.0,362040000.0,56938000000.0,7472600000.0,248090000.0,90796000.0,3666700000.0,1494500000.0,276050000.0,18037000.0,816050000.0,459800000.0,3103300000.0,130660000.0,98653000.0,65955000.0,,162540000.0,1862000000.0,645820000.0,789900000.0,4891800.0,14875000000.0,,188760000.0,4739500000.0,65851000.0,1475700000.0,,,2840600000.0,34612000.0,106200000.0,528780000.0,165230000.0,210010000.0,1646200000.0,,212500000.0,14823000.0,,71302000.0,133300000.0,40708000.0,111540000.0,51423000.0,389170000.0,250450000.0,5086900000.0,394260000.0,,2426000000.0,1280900000.0,11588000000.0,20002000000.0,23319000.0,157470000.0,87955000.0,84773000.0,172700000.0,,112830000.0,339010000.0,201200000.0,124930000.0,12293000000.0,1292400000.0,,,2447900000.0,6287200000.0,,3778800000.0,772310000.0,1196500000.0,1017700000.0,1085200000.0,632480000.0,16019000.0,5861000000.0,1551100000.0,168080000.0,92260000.0,340990000.0,2388600000.0,3807600000.0,,55657000.0,72510000.0,42528000.0,233260000.0,259050000.0,,2000900000.0,167240000.0,223300000.0,3514700000.0,1846500000.0,353530000.0,198920000.0,284640000.0,3823700000.0,736560000.0,107080000.0,49314000.0,169570000.0,99085000.0,92403000.0,,479890000.0,,69641000.0,88578000.0,401380000.0,,3331700000.0,11522000000.0,706990000.0,,120550000.0,10509000000.0,,267400000.0,59052000.0,57815000.0,,17590000.0,244380000.0,28937000.0,322170000.0,245200000.0,248790000.0,234780000.0,463340000.0,934700000.0,929820000.0,152680000.0,26941000.0,1347500000.0,204070000.0,86056000.0,258810000.0,293050000.0,,16558000000.0,475880000.0,,11651000.0,46248000.0,,826020000.0,62789000.0,65430000.0,317880000.0,6980800000.0,,289350000.0,261780000.0,264870000.0,99540000.0,829590000.0,131800000.0,11541000000.0,,9130900000.0,,611540000.0,629940000.0,51474000.0,7284800000.0,79663000.0,220980000.0,238230000.0,5736300000.0,37430000.0,1533800000.0,1534200000.0,222060000.0,49903000.0,492920000.0,121250000.0,29144000.0,28693000.0,182720000.0 +2020_01_04_04_23_Q-Exactive-HF-X-Orbitrap_6070,133940000.0,,82793000000.0,88958000.0,75654000.0,,689840000.0,1565100000.0,1183400000.0,,102020000.0,43047000.0,77420000.0,1410800000.0,191500000.0,,87108000.0,356980000.0,224100000.0,61619000.0,5641500000.0,157290000.0,372000000.0,1671700000.0,199280000.0,2244300000.0,,1315800000.0,75226000.0,184060000.0,621480000.0,182820000.0,8291600000.0,197740000.0,289680000.0,287760000.0,47634000000.0,73371000.0,4016000000.0,301290000.0,97315000.0,61043000.0,3158900000.0,2867700000.0,718170000.0,1688800000.0,63227000.0,151590000.0,,59619000.0,138460000.0,,571540000.0,1719800000.0,,28804000.0,61844000.0,541440000.0,207330000.0,6468900000.0,92395000.0,200360000.0,185490000.0,145530000.0,158070000.0,506640000.0,65780000.0,5680300000.0,404410000.0,1155100000.0,,25127000.0,,166860000.0,112020000.0,25196000.0,436130000.0,97238000.0,52740000.0,5084500000.0,490100000.0,82439000.0,116480000.0,,265710000.0,151790000.0,,68357000.0,42967000.0,,36183000.0,47339000.0,,80102000.0,50953000.0,285860000.0,285710000.0,,622260000.0,128760000.0,7275200000.0,2057600000.0,1125600000.0,501420000.0,156320000.0,3929700000.0,,311000000.0,,145720000.0,6186400000.0,1589500000.0,35600000.0,109710000.0,206630000.0,152460000.0,,1548700000.0,2081100000.0,555110000.0,2651700000.0,210920000.0,213560000.0,3425900000.0,46373000.0,41850000.0,99423000.0,968690000.0,,871980000.0,7669700.0,,195100000.0,23149000.0,46166000.0,87879000.0,185500000.0,,599430000.0,,7624500.0,540670000.0,207540000.0,4127800000.0,,,140000000.0,96986000.0,177340000.0,55749000.0,1011800000.0,,336250000.0,468190000.0,610380000.0,1164800000.0,723670000.0,21184000.0,2226000000.0,,4259700000.0,176980000.0,480520000.0,81271000.0,,223450000.0,206100000.0,505850000.0,409190000.0,119870000.0,959410000.0,938450000.0,24992000.0,66720000.0,149180000.0,,2504500000.0,194830000.0,2014200000.0,269430000.0,245140000.0,86026000.0,52678000.0,612430000.0,34562000.0,3682000000.0,149110000.0,5218800000.0,2551100000.0,259100000.0,282140000.0,217220000.0,55767000.0,1676600000.0,51886000.0,79129000.0,1846300000.0,941660000.0,1876100000.0,,,289950000.0,3320300000.0,631230000.0,21437000000.0,,130710000.0,343830000.0,98969000.0,,179970000.0,21966000.0,4017700000.0,346150000.0,109010000.0,769310000.0,2363400000.0,3166800000.0,2640400000.0,105860000.0,346300000.0,1426700000.0,40205000.0,81361000.0,59389000000.0,173140000.0,,18193000.0,,25788000.0,68107000.0,887620000.0,161820000.0,,251030000.0,350020000.0,68127000.0,741280000.0,424770000.0,98590000.0,39402000.0,58143000.0,738560000.0,320220000.0,893140000.0,508190000.0,512090000.0,25298000000.0,601220000.0,15719000000.0,46983000.0,,16749000.0,220330000.0,168220000.0,109160000.0,1274400000.0,21110000000.0,,260090000.0,473330000.0,,36247000.0,4210500000.0,1847900000.0,25755000.0,1770400000.0,37911000.0,143530000.0,7235700000.0,467240000.0,623080000.0,66298000000.0,9751400000.0,233410000.0,122670000.0,6202300000.0,3077600000.0,428600000.0,,931840000.0,432330000.0,5559200000.0,343520000.0,260540000.0,,,229800000.0,2507700000.0,670330000.0,1172300000.0,12044000.0,23330000000.0,,220750000.0,5424100000.0,26321000.0,1551100000.0,,244200000.0,3738100000.0,37350000.0,77145000.0,878840000.0,281050000.0,302400000.0,7411000.0,16615000000.0,389400000.0,44989000.0,,59266000.0,127350000.0,114290000.0,185130000.0,158110000.0,557120000.0,296690000.0,5694400000.0,615770000.0,,3713800000.0,1442800000.0,14062000000.0,28189000000.0,,196830000.0,134440000.0,215710000.0,279530000.0,9495800.0,199140000.0,392240000.0,443440000.0,238270000.0,17505000000.0,1292600000.0,,,3204600000.0,7258800000.0,,3284500000.0,976810000.0,1184600000.0,947280000.0,944950000.0,1059400000.0,174710000.0,8568900000.0,2936700000.0,275700000.0,192950000.0,186770000.0,2495900000.0,5969000000.0,49509000.0,2072900000.0,45600000.0,93356000.0,266750000.0,332210000.0,,2841500000.0,163700000.0,223760000.0,4248500000.0,2776000000.0,443580000.0,479500000.0,512420000.0,5655300000.0,997190000.0,89059000.0,,391160000.0,106370000.0,148520000.0,,652440000.0,,119430000.0,,953260000.0,34061000.0,3886600000.0,11670000000.0,567460000.0,73089000.0,305450000.0,13867000000.0,,240890000.0,104390000.0,191870000.0,,183180000.0,120890000.0,117600000.0,590030000.0,526150000.0,,343770000.0,478380000.0,1345500000.0,1125200000.0,117050000.0,83899000.0,1568700000.0,257000000.0,144380000.0,105470000.0,279800000.0,,23350000000.0,605740000.0,97364000.0,,81672000.0,124710000.0,1251700000.0,34789000.0,145420000.0,252820000.0,8153000000.0,14765000.0,250110000.0,286920000.0,680700000.0,86106000.0,1229800000.0,182320000.0,14797000000.0,97217000.0,12476000000.0,66616000.0,609610000.0,834280000.0,102660000.0,6793700000.0,144410000.0,45137000.0,543930000.0,6795200000.0,39271000.0,4859000000.0,1070800000.0,329610000.0,88740000.0,731570000.0,,17515000.0,,231650000.0 +2020_01_04_10_03_Q-Exactive-HF-X-Orbitrap_6070,,,19144000000.0,,,,14775000000.0,194180000.0,34873000.0,,,4853800.0,,181280000.0,74915000.0,,,94865000.0,12440000.0,,940270000.0,6076200.0,228330000.0,226450000.0,8651000.0,164690000.0,,147410000.0,3583700.0,,,,1286000000.0,6841400.0,60463000.0,60633000.0,8060500000.0,,804820000.0,312920000.0,,15757000.0,1369900000.0,91362000.0,65693000.0,275180000.0,6141900.0,,,,,,20777000.0,124500000.0,,,,25448000.0,,765090000.0,,39445000.0,,27934000.0,,,46149000.0,797610000.0,18815000.0,632770000.0,35792000.0,,,,,,149300000.0,,,761410000.0,74424000.0,,,,43413000.0,,,,,,,,,,,,106620000.0,,23109000.0,,921560000.0,251760000.0,145320000.0,9033200.0,7695400.0,408950000.0,,34225000.0,,,1261000000.0,64893000.0,,5920100.0,,,,223800000.0,395840000.0,,74683000.0,,,235160000.0,,,,88545000.0,,158770000.0,,,,,,,,,36450000.0,,,79502000.0,,711080000.0,,,20666000.0,,17606000.0,12833000.0,16593000.0,25323000.0,26501000.0,229820000.0,93686000.0,42019000.0,43227000.0,,222190000.0,,538830000.0,,17272000.0,,,54047000.0,10113000.0,,92389000.0,77869000.0,67936000.0,225950000.0,,,,59930000.0,479480000.0,,217330000.0,23888000.0,63753000.0,,41961000.0,9767800.0,,547850000.0,,968090000.0,526060000.0,69781000.0,70931000.0,18898000.0,,203310000.0,,,158060000.0,93325000.0,348740000.0,,62871000.0,,267810000.0,35399000.0,871020000.0,,27449000.0,15922000.0,,,,,994300000.0,,,,,439620000.0,238800000.0,,16386000.0,191410000.0,,,20394000000.0,9992400.0,,,,,,157540000.0,36124000.0,,,38587000.0,,43725000.0,,,,,70489000.0,8643000.0,258430000.0,170730000.0,,4767800000.0,94373000.0,2651000000.0,,,,2446200.0,94716000.0,11109000.0,247670000.0,5238900000.0,,,41766000.0,,,523170000.0,211380000.0,,,,,977150000.0,35840000.0,79165000.0,15363000000.0,1549000000.0,,,1069500000.0,384210000.0,159010000.0,,20251000.0,77111000.0,877400000.0,23347000.0,63451000.0,,,6878300.0,538910000.0,95925000.0,64990000.0,,4441300000.0,,,983890000.0,,412460000.0,,19115000.0,837750000.0,,,189980000.0,14640000.0,,319090000.0,,41132000.0,,,,90760000.0,,31721000.0,,135560000.0,24770000.0,1826300000.0,29448000.0,,384810000.0,134270000.0,2833400000.0,15013000000.0,,47351000.0,9564100.0,8871500.0,28111000.0,,,44138000.0,43604000.0,,3058900000.0,152220000.0,,,247830000.0,9524800000.0,,2751500000.0,62436000.0,56521000.0,485040000.0,118390000.0,18448000.0,32447000.0,1185300000.0,803150000.0,5204300.0,,60212000.0,863170000.0,463990000.0,,128900000.0,7786300.0,,,35406000.0,,484540000.0,5680400.0,,893440000.0,365810000.0,78456000.0,109500000.0,22769000.0,825600000.0,483940000.0,,,75888000.0,,,,90918000.0,,,,8336700.0,,344590000.0,1632600000.0,132000000.0,,,4976000000.0,,104590000.0,,,,2436300.0,39078000.0,,67818000.0,29312000.0,100270000.0,70939000.0,18182000.0,200480000.0,127940000.0,,,179860000.0,24838000.0,3639600.0,30686000.0,41314000.0,,4849800000.0,46553000.0,,,24328000.0,13539000.0,109680000.0,,,,1147900000.0,,,,36038000.0,,43724000.0,45129000.0,5115700000.0,28134000.0,1675200000.0,,59743000.0,187370000.0,,3373100000.0,3791200.0,,27079000.0,1072500000.0,,509790000.0,234720000.0,,,,,,,57402000.0 +2020_01_04_14_59_Q-Exactive-HF-X-Orbitrap_6070,,,25184000000.0,58631000.0,,,135860000.0,500960000.0,263980000.0,,,,,266380000.0,,,,121280000.0,95206000.0,19262000.0,1677900000.0,53589000.0,,588070000.0,30900000.0,505680000.0,,335470000.0,9287700.0,186800000.0,76296000.0,13891000.0,2016400000.0,57091000.0,50339000.0,49850000.0,14645000000.0,,1337700000.0,,,18209000.0,1254200000.0,736800000.0,101330000.0,214210000.0,17035000.0,42855000.0,,,,141340000.0,170850000.0,390770000.0,,,25932000.0,14402000.0,14898000.0,2043000000.0,21957000.0,,44714000.0,40811000.0,,118250000.0,,1839300000.0,131360000.0,451860000.0,33114000.0,,,54022000.0,30286000.0,,50963000.0,,,1217200000.0,111240000.0,,13084000.0,,58196000.0,2809700.0,,,,,,,,27363000.0,19782000.0,,172480000.0,,102520000.0,114640000.0,1912700000.0,400270000.0,246340000.0,34225000.0,15860000.0,552550000.0,,60122000.0,,53480000.0,1421700000.0,222520000.0,,43308000.0,,,,142450000.0,959960000.0,107860000.0,253440000.0,13356000.0,19798000.0,1330900000.0,,15950000.0,,277030000.0,,110040000.0,,,,,,,54646000.0,2668800000.0,99926000.0,,8715200.0,107230000.0,20222000.0,740760000.0,,,50484000.0,15300000.0,61337000.0,,52974000.0,69086000.0,51818000.0,88903000.0,405690000.0,186570000.0,141910000.0,,815600000.0,,1133700000.0,,78387000.0,,,,32071000.0,83385000.0,48128000.0,63383000.0,283610000.0,211720000.0,,,10517000.0,30807000.0,1238200000.0,15990000.0,450890000.0,38272000.0,37851000.0,,6770300.0,6846400.0,16425000.0,1086600000.0,,1187100000.0,1241500000.0,50936000.0,89255000.0,,,440600000.0,,,434600000.0,350640000.0,392790000.0,,122840000.0,,958640000.0,,8352500000.0,,124530000.0,16693000.0,,,70618000.0,,1275500000.0,,,160730000.0,,109300000.0,896910000.0,,18636000.0,393100000.0,,42877000.0,23589000000.0,29109000.0,,,,,18206000.0,219140000.0,49998000.0,,,39942000.0,,328810000.0,,,15589000.0,25949000.0,152690000.0,54719000.0,164980000.0,72478000.0,67240000.0,6257000000.0,97171000.0,4568800000.0,30065000.0,,,24336000.0,56595000.0,83519000.0,981890000.0,6762400000.0,,63110000.0,95659000.0,,,535440000.0,367080000.0,,51945000.0,56529000.0,21414000.0,2114700000.0,78266000.0,136600000.0,17506000000.0,2788100000.0,27036000.0,,1882900000.0,323970000.0,85586000.0,,190040000.0,24534000.0,1082500000.0,95794000.0,75014000.0,,,,723440000.0,360140000.0,386300000.0,,7840600000.0,,74023000.0,1578200000.0,,616780000.0,,50843000.0,1285700000.0,,,152750000.0,33854000.0,84115000.0,,4753300000.0,49929000.0,,,,35513000.0,11194000.0,71981000.0,,118080000.0,49238000.0,1550000000.0,129270000.0,371340000.0,941070000.0,535050000.0,2984000000.0,5929800000.0,11809000.0,34070000.0,10656000.0,,,,25525000.0,51421000.0,50587000.0,,4071600000.0,318580000.0,,,959450000.0,2805000000.0,,2411700000.0,218660000.0,370080000.0,300710000.0,368860000.0,142890000.0,,1952200000.0,935490000.0,26712000.0,18228000.0,29466000.0,450190000.0,1562200000.0,,121110000.0,27843000.0,22922000.0,,78119000.0,,923430000.0,42542000.0,,1040000000.0,522110000.0,142980000.0,,47213000.0,1497500000.0,320550000.0,6099000.0,36517000.0,31962000.0,,4656000.0,,149780000.0,,,,202000000.0,,1471300000.0,3478900000.0,74966000.0,,23433000.0,3663800000.0,,84110000.0,8405900.0,43528000.0,,81419000.0,26322000.0,,245790000.0,43520000.0,,75604000.0,58468000.0,379220000.0,418090000.0,23422000.0,,331500000.0,18848000.0,40910000.0,,76126000.0,,8550500000.0,195310000.0,,,,57943000.0,247180000.0,,,71925000.0,2272600000.0,,,,75905000.0,,421210000.0,,5345100000.0,50907000.0,3218900000.0,,276500000.0,434960000.0,49682000.0,1386900000.0,,22761000.0,125800000.0,1747100000.0,,457120000.0,628680000.0,65125000.0,,168280000.0,,1633800.0,,76543000.0 +2020_01_06_20_17_Q-Exactive-HF-X-Orbitrap_6070,54498000.0,,82977000000.0,226650000.0,114660000.0,,1248800000.0,2918100000.0,1127500000.0,,,33621000.0,91382000.0,2562400000.0,90632000.0,,37628000.0,709350000.0,131910000.0,64779000.0,6569000000.0,173520000.0,572190000.0,2761900000.0,428320000.0,2445100000.0,69241000.0,1866700000.0,78344000.0,299990000.0,705560000.0,205800000.0,10895000000.0,418950000.0,269580000.0,349610000.0,66453000000.0,266590000.0,7328000000.0,428190000.0,119650000.0,219070000.0,3398800000.0,4032400000.0,1040000000.0,2893700000.0,,221700000.0,,189340000.0,107700000.0,1082900000.0,889250000.0,2225800000.0,,,59514000.0,554610000.0,215800000.0,7255200000.0,101130000.0,64562000.0,297610000.0,309460000.0,216870000.0,210570000.0,,6783300000.0,572950000.0,1532300000.0,1761500000.0,28140000.0,58558000.0,124070000.0,259330000.0,64366000.0,435020000.0,451950000.0,,5504400000.0,632060000.0,97350000.0,65283000.0,,256330000.0,53023000.0,77323000.0,63278000.0,50266000.0,,124050000.0,52202000.0,18736000.0,189730000.0,60430000.0,351810000.0,455330000.0,,558430000.0,220850000.0,6462700000.0,2024300000.0,1617200000.0,729340000.0,67618000.0,4547700000.0,133560000.0,762810000.0,,171710000.0,6088300000.0,929180000.0,98619000.0,,192370000.0,454870000.0,,1471600000.0,2128200000.0,527180000.0,1164600000.0,257350000.0,317220000.0,4081000000.0,,34171000.0,194200000.0,1508500000.0,,1659100000.0,186640000.0,54190000.0,125590000.0,38984000.0,,208420000.0,334690000.0,,1012800000.0,42651000.0,34457000.0,858940000.0,103620000.0,5115000000.0,,,226360000.0,116570000.0,190610000.0,40723000.0,1050700000.0,110480000.0,159920000.0,744030000.0,945300000.0,1746200000.0,651990000.0,41508000.0,2703500000.0,187570000.0,5573200000.0,115840000.0,645800000.0,106040000.0,29655000.0,317270000.0,199330000.0,288830000.0,653160000.0,364550000.0,1120900000.0,1726500000.0,114320000.0,,143570000.0,,3024900000.0,640900000.0,2175900000.0,413870000.0,302620000.0,196050000.0,161490000.0,616510000.0,51358000.0,4691500000.0,259670000.0,6636200000.0,3710200000.0,365120000.0,364890000.0,476010000.0,,3142300000.0,82135000.0,168670000.0,2671200000.0,1678700000.0,2312500000.0,,982940000.0,528770000.0,4717200000.0,131590000.0,5623000000.0,72515000.0,581320000.0,511890000.0,106530000.0,,217850000.0,42384000.0,5223100000.0,760210000.0,246190000.0,1363700000.0,,3683500000.0,4339100000.0,,698880000.0,1447300000.0,,101430000.0,70541000000.0,,,170250000.0,,34692000.0,206280000.0,1184800000.0,261980000.0,27967000.0,,668750000.0,154670000.0,584890000.0,55060000.0,109810000.0,,,1481200000.0,352760000.0,847170000.0,673210000.0,685510000.0,33486000000.0,887980000.0,20301000000.0,169950000.0,88615000.0,,232190000.0,228530000.0,236030000.0,1532900000.0,26076000000.0,,336660000.0,709380000.0,49768000.0,58323000.0,6738300000.0,3993700000.0,200420000.0,128610000.0,121540000.0,198190000.0,9499800000.0,381740000.0,711890000.0,75166000000.0,11929000000.0,624310000.0,236260000.0,7597000000.0,4183600000.0,690700000.0,,1048800000.0,509200000.0,5955200000.0,695410000.0,384510000.0,,,178570000.0,3018400000.0,569760000.0,1605400000.0,58511000.0,22859000000.0,,472660000.0,6863400000.0,106280000.0,3192700000.0,,92123000.0,5558400000.0,50088000.0,,1112500000.0,632860000.0,387760000.0,2585500000.0,,536730000.0,32498000.0,,,391200000.0,158640000.0,311710000.0,,203640000.0,1032100000.0,8915900000.0,1208100000.0,,4413100000.0,3134800000.0,14409000000.0,11295000000.0,74428000.0,132730000.0,158910000.0,149360000.0,525170000.0,21011000.0,197960000.0,521970000.0,728650000.0,301350000.0,23889000000.0,1638300000.0,,,4483800000.0,12497000000.0,4307900000.0,5616200000.0,1207800000.0,1457500000.0,2074700000.0,1628600000.0,1177300000.0,429300000.0,11301000000.0,3379900000.0,425550000.0,141710000.0,750130000.0,2684100000.0,8116600000.0,56812000.0,366930000.0,117680000.0,106270000.0,405320000.0,711440000.0,97216000.0,3742300000.0,189820000.0,285240000.0,5289300000.0,3422300000.0,677610000.0,67253000.0,516140000.0,8482500000.0,1129600000.0,239260000.0,47789000.0,220580000.0,,342300000.0,503420000.0,880790000.0,,158590000.0,,522220000.0,,5683500000.0,11457000000.0,701670000.0,57247000.0,392780000.0,18149000000.0,58718000.0,303640000.0,157920000.0,51960000.0,118570000.0,76768000.0,70742000.0,89420000.0,922220000.0,516170000.0,106980000.0,659310000.0,1003100000.0,1584600000.0,1994000000.0,209400000.0,93883000.0,1598600000.0,631710000.0,96051000.0,326840000.0,470020000.0,,28105000000.0,900580000.0,257680000.0,,121910000.0,44980000.0,938900000.0,141670000.0,145170000.0,506100000.0,13270000000.0,,73858000.0,449300000.0,820200000.0,,1821600000.0,124970000.0,24661000000.0,179000000.0,14684000000.0,,918150000.0,962670000.0,340520000.0,6598100000.0,255380000.0,194970000.0,439010000.0,9369100000.0,,3718900000.0,1754200000.0,156240000.0,,921130000.0,276180000.0,65409000.0,54524000.0,227490000.0 +2020_01_08_16_43_Q-Exactive-HF-X-Orbitrap_6070,,,35358000000.0,69835000.0,47902000.0,,159220000.0,737820000.0,363940000.0,,,31616000.0,,592610000.0,,,5691800.0,217790000.0,182270000.0,,2201300000.0,71848000.0,176140000.0,849730000.0,49317000.0,703640000.0,,602030000.0,44595000.0,338800000.0,71867000.0,11508000.0,3957900000.0,68872000.0,153530000.0,199210000.0,22652000000.0,9220400.0,2143300000.0,226700000.0,13723000.0,76263000.0,1687100000.0,1290100000.0,218730000.0,864570000.0,,38947000.0,,,,111950000.0,237940000.0,526600000.0,,22673000.0,,182400000.0,61757000.0,3975000000.0,25026000.0,77214000.0,58310000.0,57706000.0,,212750000.0,32363000.0,2157100000.0,202020000.0,1017300000.0,,,,55579000.0,75777000.0,11617000.0,181530000.0,37743000.0,,1830100000.0,257350000.0,20116000.0,30582000.0,,157940000.0,16476000.0,,37786000.0,284540000.0,18140000.0,,,9800900.0,18378000.0,54380000.0,7324600.0,124060000.0,,138130000.0,94497000.0,2833600000.0,919170000.0,589650000.0,74098000.0,24489000.0,2282300000.0,,116520000.0,,,1873900000.0,421650000.0,17137000.0,,,77802000.0,,514820000.0,1131700000.0,170610000.0,217750000.0,90430000.0,80216000.0,1615400000.0,,,,368430000.0,,354820000.0,,,28114000.0,,,5898000.0,83271000.0,10974000000.0,177970000.0,,,159450000.0,,1764500000.0,,,151980000.0,,55350000.0,,251470000.0,66824000.0,,202180000.0,592230000.0,338330000.0,262660000.0,84326000.0,1019000000.0,,1808100000.0,,161000000.0,9081800.0,13395000.0,82959000.0,59356000.0,135900000.0,349320000.0,91989000.0,315540000.0,508940000.0,33544000.0,,,45008000.0,1163200000.0,83754000.0,623490000.0,79190000.0,189280000.0,,30304000.0,202080000.0,,2124800000.0,42465000.0,1692900000.0,1314800000.0,76783000.0,126620000.0,64743000.0,12853000.0,823550000.0,29174000.0,,582140000.0,244500000.0,605300000.0,,65015000.0,90103000.0,1616000000.0,,2031400000.0,,50011000.0,73364000.0,,,18073000.0,22221000.0,2440600000.0,102440000.0,49508000.0,255930000.0,1146400000.0,1232700000.0,1535800000.0,,138170000.0,415530000.0,,38561000.0,36577000000.0,,,24478000.0,,,49966000.0,479780000.0,116570000.0,,,153400000.0,,389070000.0,,,,,247250000.0,44956000.0,4167200000.0,58822000.0,120350000.0,9832200000.0,257330000.0,5583600000.0,47832000.0,,,49662000.0,,106160000.0,453440000.0,8829600000.0,,100190000.0,310490000.0,,30724000.0,2691500000.0,578010000.0,,,45158000.0,54721000.0,3168600000.0,174580000.0,210130000.0,32514000000.0,3843700000.0,143700000.0,,2305600000.0,1321700000.0,185320000.0,,282060000.0,233880000.0,1487300000.0,162120000.0,104460000.0,,,29135000.0,969040000.0,675500000.0,393280000.0,,12090000000.0,,92411000.0,2045400000.0,42378000.0,911290000.0,,,1670700000.0,17793000.0,,288870000.0,80590000.0,76007000.0,831910000.0,,50442000.0,12156000.0,,,47113000.0,11425000.0,3464700000.0,12590000.0,66979000.0,245940000.0,2517100000.0,282490000.0,,1654500000.0,850300000.0,5559200000.0,10364000000.0,15001000.0,115280000.0,,177810000.0,100120000.0,6660500.0,31377000.0,163010000.0,187180000.0,49917000.0,6768000000.0,651430000.0,13097000.0,23659000.0,1235000000.0,4477200000.0,,1943000000.0,431740000.0,412050000.0,1027600000.0,508090000.0,183590000.0,205800000.0,3494700000.0,683530000.0,52271000.0,37646000.0,182700000.0,454580000.0,2284600000.0,,34413000.0,28434000.0,44788000.0,103980000.0,155230000.0,,1032900000.0,119840000.0,87677000.0,1696700000.0,1047900000.0,231990000.0,218340000.0,158480000.0,2643800000.0,294610000.0,56638000.0,20585000.0,153290000.0,,29657000.0,76408000.0,278070000.0,,,,454980000.0,1243300000.0,2414600000.0,4428800000.0,342810000.0,,22366000.0,6993100000.0,,106880000.0,38702000.0,,,53211000.0,112950000.0,35243000.0,292030000.0,86823000.0,45985000.0,132520000.0,20370000.0,546600000.0,850170000.0,101060000.0,4995800.0,531100000.0,186300000.0,37148000.0,134800000.0,113690000.0,,8382600000.0,366710000.0,,,,61830000.0,295450000.0,,,128150000.0,4205400000.0,,38804000.0,138810000.0,123430000.0,,289450000.0,,8450800000.0,,5284800000.0,,323760000.0,342000000.0,101200000.0,3181300000.0,,22672000.0,226580000.0,3122500000.0,,1019100000.0,632020000.0,48404000.0,,168110000.0,,,, +2020_01_09_11_07_Q-Exactive-HF-X-Orbitrap_6070,,,50500000000.0,89269000.0,71612000.0,,232810000.0,908760000.0,553740000.0,,,,27750000.0,989060000.0,28417000.0,,13949000.0,167440000.0,83692000.0,,2859700000.0,77984000.0,364940000.0,1293600000.0,89669000.0,1533600000.0,,863720000.0,34892000.0,204280000.0,369410000.0,109610000.0,5270000000.0,146170000.0,185910000.0,105710000.0,25931000000.0,13330000.0,2608300000.0,339830000.0,74522000.0,68287000.0,2786000000.0,1570400000.0,404440000.0,1093100000.0,29727000.0,33358000.0,1226600000.0,,,1585400000.0,161880000.0,1058800000.0,,21604000.0,,206520000.0,104600000.0,3199600000.0,96610000.0,96920000.0,80130000.0,141140000.0,38922000.0,253200000.0,30583000.0,3581000000.0,197400000.0,286310000.0,,,13916000.0,60430000.0,87966000.0,13866000.0,144970000.0,43489000.0,,2492700000.0,313590000.0,42110000.0,36369000.0,,130750000.0,21859000.0,18426000.0,45302000.0,,34818000.0,85016000.0,,,15821000.0,155310000.0,70567000.0,212700000.0,43957000.0,261640000.0,38803000.0,1663500000.0,1673300000.0,728830000.0,209860000.0,31341000.0,4362000000.0,,227710000.0,,,3259600000.0,354060000.0,39871000.0,,112560000.0,67811000.0,,859130000.0,1282100000.0,173010000.0,408150000.0,131020000.0,121910000.0,2312900000.0,,,,605250000.0,,588040000.0,53942000.0,,102680000.0,,,92734000.0,202820000.0,,193090000.0,33325000.0,14720000.0,74688000.0,,2169200000.0,5037500.0,,59929000.0,56459000.0,146580000.0,,380700000.0,,98029000.0,278050000.0,643010000.0,504440000.0,258800000.0,,2468400000.0,132770000.0,2892500000.0,,232110000.0,96717000.0,,,85188000.0,241090000.0,251500000.0,110940000.0,630220000.0,769350000.0,,,36536000.0,,1979700000.0,111410000.0,688990000.0,134580000.0,152220000.0,17708000.0,103350000.0,207990000.0,,1705300000.0,151010000.0,2916300000.0,1577700000.0,117090000.0,191100000.0,227090000.0,40749000.0,1025000000.0,55499000.0,65586000.0,1509000000.0,676180000.0,1090000000.0,,439570000.0,180690000.0,2856600000.0,22211000.0,2489200000.0,,49538000.0,240660000.0,100900000.0,,26861000.0,,1686000000.0,158770000.0,72477000.0,,,1330700000.0,1484800000.0,,170710000.0,470720000.0,,30917000.0,32282000000.0,,,,,,127050000.0,376640000.0,189620000.0,12355000.0,181730000.0,384630000.0,11526000.0,352840000.0,14152000.0,75939000.0,15148000.0,,407830000.0,144910000.0,550080000.0,170970000.0,354860000.0,14281000000.0,306340000.0,8787100000.0,95722000.0,,,128120000.0,,144640000.0,566260000.0,9253900000.0,,204680000.0,586670000.0,,47235000.0,2793000000.0,824690000.0,,46108000.0,41842000.0,30031000.0,4310700000.0,247470000.0,398350000.0,36356000000.0,4873400000.0,187040000.0,,3521900000.0,2146000000.0,282870000.0,,476780000.0,196470000.0,2595100000.0,363670000.0,134570000.0,,,112660000.0,1489200000.0,135370000.0,250760000.0,14710000.0,12358000000.0,31721000.0,66848000.0,3472900000.0,49056000.0,1511600000.0,3343900000.0,,2234000000.0,37952000.0,,390490000.0,95775000.0,197220000.0,24603000.0,8538200000.0,125590000.0,19012000.0,,,73605000.0,46013000.0,118990000.0,,183850000.0,306110000.0,4573800000.0,403240000.0,5173600000.0,2318500000.0,978900000.0,6210400000.0,13877000000.0,,86454000.0,36510000.0,171580000.0,207890000.0,9640500.0,79970000.0,248620000.0,202410000.0,66467000.0,11376000000.0,994140000.0,,,2357000000.0,5796100000.0,,2164800000.0,567450000.0,533450000.0,796170000.0,768190000.0,400760000.0,18984000.0,6478000000.0,916020000.0,59275000.0,28593000.0,156780000.0,926330000.0,3795600000.0,,229520000.0,20752000.0,22436000.0,158910000.0,442930000.0,,2139700000.0,8714400.0,104920000.0,2652500000.0,1072500000.0,382820000.0,196650000.0,202840000.0,3166000000.0,436620000.0,77923000.0,51356000.0,143480000.0,69555000.0,66768000.0,216200000.0,257440000.0,,,,261380000.0,2025500000.0,2419800000.0,7228500000.0,400440000.0,,89769000.0,7403500000.0,,91453000.0,47106000.0,143020000.0,,24732000.0,47514000.0,,384440000.0,241860000.0,86772000.0,262060000.0,202210000.0,500360000.0,812250000.0,103500000.0,44090000.0,657310000.0,314100000.0,122450000.0,64010000.0,375210000.0,,14916000000.0,341710000.0,,,71365000.0,45618000.0,418610000.0,4742600.0,39464000.0,269770000.0,5225000000.0,16590000.0,,146320000.0,372940000.0,,632950000.0,,9634700000.0,,7269100000.0,,496120000.0,380140000.0,68917000.0,3419800000.0,51740000.0,47955000.0,219380000.0,4044700000.0,,1938000000.0,1327800000.0,51288000.0,,,31508000.0,40381000.0,19093000.0,173270000.0 +2020_01_15_13_56_Q-Exactive-HF-X-Orbitrap_6070,,,16610000000.0,128810000.0,,7535200.0,,240530000.0,276730000.0,30679000.0,,,9779700.0,360360000.0,54193000.0,,,167470000.0,,17727000.0,769330000.0,10392000.0,107720000.0,616510000.0,108540000.0,384030000.0,42537000.0,160940000.0,51418000.0,24859000.0,17301000.0,32164000.0,2507300000.0,,,77868000.0,10621000000.0,40290000.0,1328800000.0,79503000.0,158960000.0,84113000.0,1044100000.0,526790000.0,220640000.0,493880000.0,28886000.0,43187000.0,,13082000.0,21098000.0,69757000.0,259800000.0,178290000.0,,,76316000.0,125840000.0,178870000.0,1545800000.0,44202000.0,54573000.0,,,,,,1333800000.0,,446910000.0,,,3246600.0,24844000.0,91271000.0,,547880000.0,84860000.0,53623000.0,1065700000.0,110610000.0,36764000.0,115980000.0,,,,26877000.0,108150000.0,78075000.0,3885800.0,,3423000.0,34095000.0,114520000.0,14269000.0,,143090000.0,,27857000.0,45758000.0,2429700000.0,824210000.0,330780000.0,,17828000.0,2573000000.0,,187150000.0,,7103100.0,83077000.0,89628000.0,,,,32649000.0,,182290000.0,590830000.0,80101000.0,240290000.0,328810000.0,43028000.0,1126100000.0,23494000.0,,51830000.0,246190000.0,,194680000.0,82088000.0,11731000.0,32276000.0,47916000.0,,,75196000.0,,6562700.0,,,,25752000.0,1353700000.0,,,46670000.0,,80138000.0,3503000.0,235340000.0,,91192000.0,73613000.0,217730000.0,477250000.0,84563000.0,84597000.0,295510000.0,138690000.0,955860000.0,,163390000.0,29916000.0,,240560000.0,53479000.0,83526000.0,42566000.0,287710000.0,73755000.0,4301100.0,6426300.0,,14919000.0,,171200000.0,37954000.0,121300000.0,,68134000.0,55531000.0,34677000.0,268410000.0,8548300.0,1231500000.0,,1554700000.0,954770000.0,32522000.0,98582000.0,70235000.0,28886000.0,418950000.0,,,982960000.0,285380000.0,113430000.0,,107280000.0,132730000.0,230400000.0,,8408800000.0,24810000.0,75644000.0,52724000.0,46024000.0,,149740000.0,10417000.0,996920000.0,,145150000.0,305160000.0,,409560000.0,612320000.0,11037000.0,50980000.0,791070000.0,32576000.0,18018000.0,8200400000.0,47514000.0,16596000.0,4553500.0,,,,315620000.0,99717000.0,13609000.0,,,59006000.0,183810000.0,,56542000.0,73568000.0,6601400.0,360890000.0,25035000.0,144160000.0,,60100000.0,3459600000.0,501240000.0,5684100000.0,66225000.0,85696000.0,,30512000.0,171920000.0,27863000.0,253440000.0,2731900000.0,12382000.0,99244000.0,139810000.0,,,1589100000.0,1268600000.0,,,23122000.0,118800000.0,1491300000.0,144940000.0,87027000.0,7962600000.0,2546600000.0,166140000.0,81143000.0,1285900000.0,771150000.0,91832000.0,17585000.0,96574000.0,52630000.0,1161400000.0,217690000.0,352600000.0,,,49114000.0,167200000.0,590810000.0,109230000.0,7430600.0,9307100000.0,5366400.0,231050000.0,4531800000.0,,953420000.0,3711700.0,31898000.0,777270000.0,,8318100.0,402790000.0,30972000.0,174910000.0,,4137000000.0,87272000.0,,6572200.0,12269000.0,96970000.0,69205000.0,65308000.0,12459000.0,,111260000.0,3905100000.0,123790000.0,1591100000.0,909050000.0,205920000.0,3065200000.0,,43700000.0,46485000.0,61341000.0,,18000000.0,7606300.0,,33904000.0,103300000.0,80040000.0,6344000000.0,522280000.0,43915000.0,,693650000.0,3969800000.0,,540940000.0,212530000.0,304030000.0,168240000.0,647150000.0,97272000.0,17044000.0,722820000.0,1039900000.0,,97563000.0,113910000.0,165780000.0,1300600000.0,,,45051000.0,5129000.0,74014000.0,93039000.0,,1028800000.0,61421000.0,91937000.0,478730000.0,1203200000.0,482320000.0,154770000.0,,145320000.0,93078000.0,44465000.0,43781000.0,141140000.0,,,,311040000.0,,,244060000.0,21452000.0,,815530000.0,5048900000.0,126960000.0,,37639000.0,2986200000.0,,,62851000.0,30934000.0,83691000.0,,,88495000.0,136940000.0,309770000.0,14416000.0,231730000.0,119430000.0,187340000.0,513550000.0,63440000.0,13611000.0,608720000.0,37556000.0,38838000.0,,88781000.0,,3913400000.0,191410000.0,,2430900.0,,,,20443000.0,35860000.0,184260000.0,1304200000.0,5802100.0,,282770000.0,119480000.0,105450000.0,921750000.0,63274000.0,2818100000.0,51392000.0,4384400000.0,10862000.0,182660000.0,302020000.0,35423000.0,396310000.0,39577000.0,23881000.0,,3374400000.0,11057000.0,995660000.0,,19689000.0,5789300.0,,,,,40183000.0 +2020_01_20_15_10_Q-Exactive-HF-X-Orbitrap_6070,350360000.0,,106720000000.0,194540000.0,234650000.0,,1362300000.0,3426300000.0,1782300000.0,58810000.0,96315000.0,103580000.0,150890000.0,3266000000.0,151360000.0,54347000.0,88056000.0,713020000.0,313150000.0,93349000.0,7639100000.0,382720000.0,897030000.0,2565100000.0,252030000.0,3646700000.0,98760000.0,1986000000.0,114360000.0,745620000.0,1099900000.0,150720000.0,14999000000.0,483880000.0,714350000.0,202960000.0,68747000000.0,124030000.0,6555000000.0,588720000.0,327710000.0,860700000.0,5938200000.0,2604000000.0,1436900000.0,3973700000.0,,458350000.0,,48184000.0,199420000.0,170120000.0,3604200000.0,2123700000.0,,74007000.0,109100000.0,2004500000.0,331090000.0,8505400000.0,294860000.0,267260000.0,319590000.0,278770000.0,160850000.0,693450000.0,137640000.0,5822400000.0,1033000000.0,2040000000.0,774000000.0,54220000.0,88888000.0,249570000.0,333520000.0,147190000.0,727640000.0,202190000.0,109530000.0,6658200000.0,785780000.0,206100000.0,103770000.0,40290000.0,481160000.0,116980000.0,,228870000.0,68678000.0,102360000.0,193640000.0,88877000.0,12042000.0,257680000.0,170560000.0,278570000.0,519810000.0,63776000.0,780370000.0,220410000.0,8175400000.0,3783900000.0,2179500000.0,827770000.0,94686000.0,2419800000.0,,407870000.0,,200390000.0,6601100000.0,1080900000.0,,221290000.0,2044100000.0,512210000.0,21837000.0,1681900000.0,3170800000.0,747810000.0,1497800000.0,665560000.0,397800000.0,5518800000.0,26596000.0,114820000.0,323930000.0,2084500000.0,,2183200000.0,207350000.0,,498460000.0,25076000.0,37619000.0,251260000.0,620980000.0,,1015400000.0,,81224000.0,1485000000.0,178540000.0,7041900000.0,,,246360000.0,200710000.0,251830000.0,49764000.0,1101900000.0,,368450000.0,1126000000.0,1721200000.0,2326200000.0,1206000000.0,115220000.0,2987600000.0,96511000.0,10099000000.0,187090000.0,926440000.0,256180000.0,74516000.0,365110000.0,297290000.0,860080000.0,773750000.0,275850000.0,1525600000.0,2272200000.0,227030000.0,,227610000.0,141240000.0,3673200000.0,478860000.0,2251200000.0,532930000.0,307780000.0,264780000.0,253210000.0,1083000000.0,,4060000000.0,204560000.0,7215100000.0,3580200000.0,342270000.0,879030000.0,422810000.0,94416000.0,3612900000.0,119550000.0,228600000.0,3444900000.0,1009700000.0,2656200000.0,,1434100000.0,587790000.0,6589600000.0,155980000.0,9693000000.0,,291310000.0,651570000.0,376320000.0,,173810000.0,,6098400000.0,822240000.0,294300000.0,1341000000.0,6062100000.0,10177000000.0,5434700000.0,258190000.0,703190000.0,1331400000.0,96744000.0,218210000.0,100860000000.0,100900000.0,102500000.0,104340000.0,,,247120000.0,2028400000.0,647440000.0,54424000.0,,409460000.0,64918000.0,1355400000.0,88066000.0,201100000.0,32212000.0,127380000.0,1286700000.0,756370000.0,1328400000.0,985310000.0,1307900000.0,37498000000.0,917730000.0,17075000000.0,191180000.0,74706000.0,42159000.0,402430000.0,232530000.0,278140000.0,2720200000.0,29993000000.0,,518530000.0,1435000000.0,,118990000.0,9380300000.0,2382100000.0,147510000.0,184230000.0,307250000.0,273570000.0,9967800000.0,841600000.0,1181400000.0,87268000000.0,14146000000.0,569580000.0,140650000.0,9896500000.0,6317200000.0,768330000.0,,1426500000.0,456070000.0,6828900000.0,966110000.0,650170000.0,67566000.0,75675000.0,554770000.0,4631500000.0,924170000.0,1295500000.0,14712000.0,34077000000.0,44888000.0,620660000.0,11044000000.0,135960000.0,3500200000.0,83786000.0,230370000.0,6616400000.0,14209000.0,90632000.0,1434700000.0,367900000.0,641420000.0,3284900000.0,,692440000.0,87169000.0,,609830000.0,204670000.0,173000000.0,433790000.0,97391000.0,773810000.0,858620000.0,11229000000.0,1554500000.0,,5448600000.0,2936900000.0,18638000000.0,29844000000.0,75779000.0,330780000.0,250380000.0,181470000.0,1131700000.0,1298300000.0,194730000.0,760350000.0,1004300000.0,310620000.0,24685000000.0,1134000000.0,,51750000.0,5198300000.0,11201000000.0,,3802000000.0,1616000000.0,1594800000.0,2276200000.0,2787500000.0,1231200000.0,526270000.0,14189000000.0,3927500000.0,276290000.0,241550000.0,1009700000.0,2493300000.0,9080200000.0,,4339100000.0,122770000.0,207210000.0,426190000.0,1398500000.0,,4501100000.0,464800000.0,563140000.0,5832300000.0,2609600000.0,863190000.0,360960000.0,738430000.0,9114400000.0,1689700000.0,264500000.0,170370000.0,459850000.0,288440000.0,401340000.0,,1002300000.0,,235300000.0,,895280000.0,,8935200000.0,21867000000.0,1574400000.0,113930000.0,150890000.0,16965000000.0,,555480000.0,344830000.0,257300000.0,16716000.0,257420000.0,212890000.0,277210000.0,1155400000.0,588620000.0,74278000.0,932930000.0,822020000.0,1531200000.0,2122300000.0,192950000.0,197030000.0,2821400000.0,343840000.0,259790000.0,475450000.0,1158800000.0,55096000.0,32889000000.0,1468600000.0,,,138660000.0,247980000.0,2108700000.0,114050000.0,265620000.0,881430000.0,14644000000.0,,487350000.0,630910000.0,866270000.0,,3023700000.0,179120000.0,20944000000.0,474640000.0,18128000000.0,,1275500000.0,1167800000.0,333630000.0,5736000000.0,258460000.0,158770000.0,572460000.0,10934000000.0,32338000.0,4576700000.0,1879400000.0,661420000.0,109990000.0,349540000.0,433690000.0,111790000.0,589790000.0,313040000.0 +2020_02_05_20_55_Q-Exactive-HF-X-Orbitrap_6070,311950000.0,62610000.0,102460000000.0,211140000.0,173540000.0,,22349000.0,3312300000.0,1881500000.0,,36886000.0,69047000.0,28614000.0,2169200000.0,145200000.0,,83666000.0,352080000.0,107000000.0,72830000.0,6011300000.0,202160000.0,228620000.0,2273900000.0,368710000.0,2848600000.0,27344000.0,2075100000.0,155630000.0,637390000.0,949200000.0,188040000.0,11463000000.0,594860000.0,472060000.0,315050000.0,63591000000.0,60760000.0,5896200000.0,493470000.0,65427000.0,676180000.0,5109400000.0,3364000000.0,551710000.0,3335200000.0,151680000.0,262190000.0,2757300000.0,,132800000.0,88911000.0,3604100000.0,2109700000.0,,90391000.0,149910000.0,1054700000.0,420540000.0,8930600000.0,169320000.0,247760000.0,184660000.0,239590000.0,,538600000.0,80729000.0,5930400000.0,965420000.0,1468400000.0,,61773000.0,29462000.0,169290000.0,300640000.0,58365000.0,499260000.0,196120000.0,,5594400000.0,701780000.0,101230000.0,67629000.0,26267000.0,533180000.0,93153000.0,,31718000.0,541960000.0,,92679000.0,38325000.0,88911000.0,603010000.0,128010000.0,353480000.0,239920000.0,60488000.0,707380000.0,142990000.0,7265600000.0,3266600000.0,1689600000.0,689140000.0,71088000.0,10258000000.0,,376000000.0,,162430000.0,4946600000.0,1797500000.0,77945000.0,95943000.0,74659000.0,166410000.0,48250000.0,1540300000.0,3536600000.0,1015300000.0,1280700000.0,332690000.0,314750000.0,4155200000.0,,47248000.0,264630000.0,1627600000.0,,1829500000.0,136090000.0,49069000.0,379470000.0,42589000.0,50932000.0,137600000.0,447790000.0,,926780000.0,36669000.0,12973000.0,457650000.0,59611000.0,6243100000.0,,,302150000.0,843560000.0,220800000.0,104820000.0,1032400000.0,417440000.0,299700000.0,743540000.0,1336600000.0,1485200000.0,1089100000.0,174670000.0,2097000000.0,548490000.0,6141500000.0,185400000.0,854250000.0,162780000.0,33903000.0,365130000.0,319730000.0,775270000.0,432680000.0,178090000.0,861220000.0,1762800000.0,62100000.0,,46544000.0,,3637300000.0,499100000.0,2019200000.0,517500000.0,334780000.0,120980000.0,183850000.0,516320000.0,,5256200000.0,337450000.0,4933300000.0,1694600000.0,263670000.0,665090000.0,309140000.0,114440000.0,3126500000.0,108920000.0,120470000.0,2793200000.0,1484300000.0,1695700000.0,,1115500000.0,375460000.0,5044000000.0,133830000.0,23957000000.0,,349370000.0,368290000.0,183940000.0,336680000.0,70576000.0,45106000.0,5361000000.0,462760000.0,189300000.0,1212400000.0,2975000000.0,8159000000.0,4094900000.0,,498220000.0,1442900000.0,44697000.0,139360000.0,78517000000.0,205150000.0,44497000.0,112130000.0,31460000.0,,173760000.0,1535500000.0,251170000.0,25299000.0,,667240000.0,132330000.0,923650000.0,83633000.0,87830000.0,121980000.0,85884000.0,1131100000.0,388020000.0,2246300000.0,1610500000.0,779970000.0,33288000000.0,855350000.0,19438000000.0,316440000.0,,74561000.0,315090000.0,162580000.0,170240000.0,1283600000.0,21789000000.0,,272830000.0,964460000.0,13237000.0,,7069500000.0,1918400000.0,65017000.0,135890000.0,318980000.0,138370000.0,11826000000.0,738410000.0,990670000.0,86480000000.0,12310000000.0,505860000.0,118550000.0,8425200000.0,4418800000.0,1927000000.0,37450000.0,948810000.0,454450000.0,4794700000.0,649490000.0,398050000.0,86172000.0,94902000.0,344930000.0,3975900000.0,872310000.0,985320000.0,36503000.0,30557000000.0,62454000.0,477220000.0,7805900000.0,226790000.0,2891800000.0,18757000.0,206080000.0,4438600000.0,78382000.0,192110000.0,1406400000.0,473610000.0,457370000.0,,22085000000.0,678930000.0,20911000.0,,54017000.0,313630000.0,38212000.0,357460000.0,105730000.0,588040000.0,935790000.0,10034000000.0,1083000000.0,,4384900000.0,2817000000.0,17041000000.0,24984000000.0,164870000.0,215410000.0,222560000.0,169260000.0,494190000.0,63223000.0,175550000.0,517490000.0,633670000.0,141610000.0,25989000000.0,1370400000.0,,26829000.0,4948700000.0,53255000000.0,,4030600000.0,1266500000.0,1339400000.0,1480800000.0,1953900000.0,654210000.0,287670000.0,11362000000.0,2751700000.0,369440000.0,34104000.0,628380000.0,2814900000.0,8957200000.0,,123440000.0,24081000.0,250050000.0,294130000.0,904220000.0,20081000.0,3832200000.0,196770000.0,262880000.0,5499800000.0,3793800000.0,1047700000.0,316560000.0,614170000.0,7644100000.0,590500000.0,232760000.0,80170000.0,455940000.0,,175240000.0,,1238300000.0,,100350000.0,,296510000.0,,6109700000.0,14349000000.0,1210600000.0,27102000.0,233310000.0,13848000000.0,,416990000.0,311800000.0,203980000.0,,119550000.0,172400000.0,186870000.0,973950000.0,732140000.0,89290000.0,726540000.0,570860000.0,1418300000.0,2057000000.0,242390000.0,139680000.0,1976800000.0,609540000.0,167940000.0,551920000.0,521610000.0,,20472000000.0,726740000.0,74650000.0,119540000.0,68938000.0,126640000.0,931180000.0,73653000.0,173060000.0,496790000.0,17031000000.0,12654000.0,,453020000.0,836630000.0,,2012100000.0,,16766000000.0,319640000.0,16931000000.0,,989990000.0,1268400000.0,217860000.0,6455500000.0,232740000.0,95020000.0,518620000.0,8242700000.0,27394000.0,3375900000.0,1572800000.0,507850000.0,,,178500000.0,131120000.0,190490000.0,213130000.0 +2020_02_10_15_41_Q-Exactive-HF-X-Orbitrap_6070,,34589000.0,58597000000.0,718590000.0,,,,2156700000.0,1150400000.0,188750000.0,130090000.0,,194760000.0,2584200000.0,304930000.0,211150000.0,,994800000.0,69128000.0,494930000.0,4617800000.0,65211000.0,249600000.0,4754100000.0,667630000.0,2843300000.0,180840000.0,1701500000.0,164330000.0,147060000.0,79582000.0,173530000.0,12123000000.0,,,478740000.0,55270000000.0,291050000.0,9308800000.0,199310000.0,1564900000.0,719880000.0,8393800000.0,2472600000.0,1551500000.0,3287100000.0,388220000.0,220750000.0,2522400000.0,292830000.0,276290000.0,,2361600000.0,963060000.0,96818000.0,50403000.0,495690000.0,1071800000.0,1222700000.0,5842600000.0,145040000.0,317370000.0,,595100000.0,332200000.0,126280000.0,134640000.0,7418600000.0,,1589800000.0,301700000.0,173240000.0,,477680000.0,816650000.0,19478000.0,4335900000.0,694980000.0,201150000.0,6846000000.0,491610000.0,667480000.0,542220000.0,,,395490000.0,70257000.0,325910000.0,272620000.0,,84273000.0,23815000.0,225850000.0,428990000.0,25751000.0,64593000.0,770010000.0,66540000.0,475810000.0,708160000.0,9783100000.0,3830200000.0,2225200000.0,,106840000.0,16359000000.0,46326000.0,514140000.0,,102740000.0,719080000.0,417240000.0,,,21956000.0,226220000.0,15932000.0,1099200000.0,2375700000.0,449040000.0,1382600000.0,1693900000.0,289930000.0,5305200000.0,285470000.0,155140000.0,166330000.0,2398600000.0,27475000.0,1564800000.0,320680000.0,154220000.0,503580000.0,407810000.0,79186000.0,40500000.0,564550000.0,24193000000.0,443740000.0,99889000.0,147420000.0,342280000.0,322250000.0,7186200000.0,63735000.0,,233530000.0,13940000.0,71534000.0,81967000.0,797550000.0,100060000.0,205300000.0,156500000.0,1381400000.0,2668800000.0,713950000.0,459480000.0,2021600000.0,750660000.0,5223900000.0,,1465200000.0,185110000.0,133870000.0,1532400000.0,458690000.0,604800000.0,434110000.0,795700000.0,373390000.0,361590000.0,168510000.0,29450000.0,132090000.0,108980000.0,2286800000.0,627630000.0,1777800000.0,,227450000.0,286310000.0,326640000.0,1927100000.0,117070000.0,7737500000.0,262480000.0,8365900000.0,4119400000.0,354580000.0,902580000.0,440610000.0,,3034100000.0,70149000.0,130630000.0,4970700000.0,1857400000.0,473150000.0,,706000000.0,916950000.0,2749500000.0,181230000.0,24025000000.0,67434000.0,73122000.0,122680000.0,306430000.0,,358930000.0,236010000.0,4125300000.0,,1378700000.0,1357700000.0,,3797900000.0,4161900000.0,105150000.0,444530000.0,2954700000.0,521490000.0,62526000.0,31326000000.0,263730000.0,28947000.0,110570000.0,132820000.0,,,1447700000.0,420180000.0,241100000.0,,,112260000.0,700030000.0,215030000.0,647590000.0,730050000.0,174690000.0,2960300000.0,303330000.0,799640000.0,,825480000.0,25575000000.0,2589000000.0,23028000000.0,251310000.0,568040000.0,,464420000.0,617550000.0,260460000.0,1694600000.0,10930000000.0,226710000.0,318270000.0,1432400000.0,111740000.0,,10112000000.0,3555200000.0,,201960000.0,83822000.0,1240600000.0,11747000000.0,1139700000.0,985260000.0,37823000000.0,13627000000.0,1364100000.0,477640000.0,6596100000.0,3586000000.0,679440000.0,266960000.0,543670000.0,269260000.0,4655100000.0,736060000.0,2089200000.0,153760000.0,75024000.0,528180000.0,1210100000.0,1750300000.0,1200600000.0,145500000.0,25435000000.0,122890000.0,1499800000.0,19694000000.0,25352000.0,3291300000.0,180260000.0,2848500000.0,3786000000.0,,266810000.0,1822200000.0,246700000.0,528690000.0,,,703150000.0,114690000.0,81615000.0,115640000.0,293400000.0,486330000.0,516400000.0,,92050000.0,930890000.0,15124000000.0,1314100000.0,1049000000.0,4490000000.0,1948700000.0,13683000000.0,,804030000.0,164560000.0,690990000.0,60878000.0,179850000.0,2132000000.0,,314900000.0,1084700000.0,511150000.0,32608000000.0,1862800000.0,45887000.0,101330000.0,6213900000.0,44343000000.0,,2111500000.0,1016200000.0,1204600000.0,1014500000.0,3961700000.0,523290000.0,312440000.0,3697700000.0,3561500000.0,,827930000.0,800770000.0,858590000.0,8031000000.0,,127700000.0,331310000.0,157130000.0,387660000.0,955570000.0,74924000.0,3601200000.0,106800000.0,746040000.0,2226900000.0,3128400000.0,4608400000.0,810690000.0,,1473700000.0,360100000.0,507540000.0,481370000.0,580300000.0,,344480000.0,,2245800000.0,,101370000.0,619760000.0,337920000.0,,3578200000.0,23861000000.0,906860000.0,31658000.0,507650000.0,9029200000.0,,47776000.0,773380000.0,92409000.0,419510000.0,466970000.0,58240000.0,484680000.0,1246900000.0,2457800000.0,89484000.0,1064200000.0,807270000.0,1727300000.0,3478700000.0,405440000.0,72045000.0,3997000000.0,346950000.0,369550000.0,335390000.0,675150000.0,53022000.0,20246000000.0,1541700000.0,,28555000.0,,46901000.0,,419760000.0,134240000.0,654190000.0,10475000000.0,25491000.0,,1369000000.0,1064900000.0,,4334800000.0,389610000.0,13010000000.0,355520000.0,22346000000.0,180720000.0,1677500000.0,1323800000.0,225650000.0,1234800000.0,195000000.0,174900000.0,284520000.0,17693000000.0,122540000.0,5218000000.0,625960000.0,61393000.0,,,,262570000.0,13871000.0,145900000.0 +2020_02_11_10_35_Q-Exactive-HF-X-Orbitrap_6070,,30944000.0,53062000000.0,383700000.0,,33229000.0,,1747300000.0,903190000.0,167270000.0,97290000.0,,227580000.0,2550900000.0,194060000.0,105190000.0,,729830000.0,71552000.0,339300000.0,4011600000.0,90888000.0,176080000.0,4490900000.0,711230000.0,2020600000.0,183320000.0,1499300000.0,142480000.0,129970000.0,162360000.0,154410000.0,11200000000.0,,,188850000.0,47081000000.0,204300000.0,8238000000.0,98994000.0,1203000000.0,434450000.0,5695300000.0,1648800000.0,1089000000.0,2724900000.0,407160000.0,195510000.0,1558400000.0,173510000.0,181280000.0,,1940700000.0,857740000.0,54173000.0,25443000.0,161120000.0,893720000.0,812470000.0,6259400000.0,160380000.0,349600000.0,53614000.0,275520000.0,420690000.0,139440000.0,56231000.0,6901400000.0,,1336300000.0,,110520000.0,,426650000.0,574610000.0,24527000.0,3436300000.0,476790000.0,209730000.0,4832000000.0,557680000.0,276250000.0,363950000.0,,,241480000.0,140680000.0,325400000.0,307750000.0,55656000.0,65220000.0,,184970000.0,463890000.0,99064000.0,125270000.0,736140000.0,95367000.0,403330000.0,273120000.0,13171000000.0,3275300000.0,1947000000.0,,82986000.0,6798000000.0,,634380000.0,,90216000.0,596590000.0,413910000.0,,,10287000.0,306360000.0,,831090000.0,2057100000.0,472540000.0,1078700000.0,1506800000.0,191650000.0,4241200000.0,346460000.0,109270000.0,150750000.0,1907500000.0,13180000.0,1662200000.0,205260000.0,124880000.0,390430000.0,214180000.0,25163000.0,43791000.0,435530000.0,17602000000.0,184440000.0,75389000.0,114470000.0,905540000.0,341560000.0,5374700000.0,136450000.0,20572000.0,446960000.0,18487000.0,44927000.0,46046000.0,661090000.0,154640000.0,333090000.0,290980000.0,429260000.0,2255000000.0,537500000.0,351430000.0,1736900000.0,853950000.0,4023300000.0,,1415500000.0,163680000.0,235420000.0,494920000.0,223110000.0,546500000.0,531110000.0,1024500000.0,221890000.0,186320000.0,139990000.0,,83383000.0,71901000.0,1782600000.0,453000000.0,1247800000.0,,238730000.0,352720000.0,332910000.0,1599800000.0,37356000.0,4757000000.0,223100000.0,7330900000.0,3399500000.0,199860000.0,654250000.0,479470000.0,158910000.0,1975600000.0,65523000.0,100360000.0,4080200000.0,1845600000.0,525060000.0,,899770000.0,629560000.0,2552200000.0,151810000.0,20434000000.0,141380000.0,35199000.0,97359000.0,248110000.0,,658000000.0,164750000.0,4399700000.0,,777460000.0,1164700000.0,,3306100000.0,3642800000.0,89639000.0,495080000.0,3284800000.0,566670000.0,118410000.0,29709000000.0,303440000.0,29144000.0,131460000.0,98651000.0,,,1039700000.0,467110000.0,200960000.0,473710000.0,,299110000.0,550480000.0,265620000.0,418740000.0,630230000.0,125110000.0,2221500000.0,309080000.0,810910000.0,,426440000.0,19785000000.0,2190300000.0,23008000000.0,172770000.0,466420000.0,,350850000.0,642440000.0,286620000.0,1264600000.0,11037000000.0,143490000.0,245340000.0,1351500000.0,78809000.0,,8718500000.0,3703800000.0,,196210000.0,283370000.0,888530000.0,10341000000.0,865030000.0,721850000.0,29978000000.0,10854000000.0,1671500000.0,289800000.0,6286600000.0,2293100000.0,726280000.0,201930000.0,586140000.0,360140000.0,5337000000.0,764710000.0,1957500000.0,148320000.0,77464000.0,454790000.0,947680000.0,1412200000.0,995660000.0,124220000.0,22484000000.0,133480000.0,1258300000.0,16261000000.0,27375000.0,4823500000.0,222940000.0,2119700000.0,4121400000.0,,136500000.0,1635600000.0,212890000.0,495550000.0,,14186000000.0,1005200000.0,163240000.0,214830000.0,96726000.0,270460000.0,352400000.0,520010000.0,37099000.0,59103000.0,670130000.0,19762000000.0,746250000.0,1007600000.0,4387900000.0,995580000.0,10615000000.0,,848430000.0,197040000.0,479640000.0,,224430000.0,1473300000.0,,186440000.0,698780000.0,430640000.0,29325000000.0,1093800000.0,,112130000.0,5234500000.0,18105000000.0,,1999400000.0,1028700000.0,974890000.0,,3324500000.0,587390000.0,362160000.0,3094700000.0,3732700000.0,,606150000.0,829740000.0,496110000.0,6567000000.0,,,326200000.0,75834000.0,361360000.0,678840000.0,14468000.0,1923900000.0,247740000.0,698410000.0,1766900000.0,3225400000.0,3281300000.0,646520000.0,,735200000.0,581360000.0,399710000.0,287530000.0,320680000.0,,233910000.0,,1933100000.0,,56467000.0,192420000.0,493900000.0,,3484100000.0,14129000000.0,734960000.0,26232000.0,465010000.0,3676500000.0,,177710000.0,478720000.0,108100000.0,240770000.0,338710000.0,22997000.0,640900000.0,923640000.0,1832700000.0,106350000.0,981940000.0,953900000.0,1306600000.0,2934000000.0,512750000.0,119680000.0,4431100000.0,271550000.0,256110000.0,348850000.0,512560000.0,,13045000000.0,1436700000.0,,118650000.0,,78078000.0,,340320000.0,223970000.0,806440000.0,9408200000.0,69125000.0,,1014600000.0,1287500000.0,418710000.0,3710700000.0,368170000.0,10844000000.0,409030000.0,21068000000.0,200160000.0,1066900000.0,1215700000.0,202620000.0,1069100000.0,263230000.0,137560000.0,211710000.0,15593000000.0,95935000.0,5089600000.0,582550000.0,62376000.0,,,,199650000.0,13543000.0,44671000.0 +2020_02_12_05_06_Q-Exactive-HF-X-Orbitrap_6070,,,57939000000.0,338960000.0,,76125000.0,,2722100000.0,1072600000.0,175110000.0,60125000.0,,258030000.0,2692600000.0,331060000.0,90704000.0,,1124800000.0,39166000.0,426590000.0,4212000000.0,101380000.0,837790000.0,4330200000.0,868110000.0,2570600000.0,122550000.0,1829800000.0,287430000.0,181820000.0,102840000.0,188600000.0,12977000000.0,,61497000.0,691460000.0,54090000000.0,338740000.0,10373000000.0,353640000.0,1325100000.0,489080000.0,6042000000.0,2083400000.0,1490300000.0,3479600000.0,337270000.0,220920000.0,,671390000.0,83511000.0,,2600700000.0,1159700000.0,23363000.0,33530000.0,325920000.0,1027200000.0,1078900000.0,7210700000.0,262100000.0,419270000.0,68571000.0,578920000.0,310240000.0,,190240000.0,6955200000.0,,2065200000.0,434040000.0,100170000.0,25221000.0,446420000.0,687210000.0,,4202200000.0,702020000.0,135070000.0,6543600000.0,300270000.0,486760000.0,758360000.0,,,225100000.0,92536000.0,360900000.0,237710000.0,116260000.0,129020000.0,20157000.0,340710000.0,349230000.0,45821000.0,62634000.0,1165300000.0,76297000.0,367100000.0,335720000.0,10067000000.0,3552100000.0,2017000000.0,,128930000.0,15243000000.0,,820440000.0,,52607000.0,355600000.0,572680000.0,,,1651600000.0,101750000.0,49753000.0,1515500000.0,2142900000.0,677280000.0,1391800000.0,1487700000.0,152920000.0,5790000000.0,395860000.0,168730000.0,240610000.0,1769400000.0,131130000.0,1597800000.0,256150000.0,198970000.0,547800000.0,279470000.0,76951000.0,105930000.0,668500000.0,27535000000.0,,57064000.0,91950000.0,401690000.0,306940000.0,6666000000.0,68662000.0,,309570000.0,104100000.0,133580000.0,57940000.0,991070000.0,169700000.0,273030000.0,396150000.0,1049200000.0,2852000000.0,378940000.0,683720000.0,1551800000.0,864350000.0,4956600000.0,,1626600000.0,,152430000.0,309990000.0,792130000.0,661460000.0,563840000.0,835360000.0,338330000.0,,323400000.0,19690000.0,154570000.0,115860000.0,2177300000.0,470740000.0,2025800000.0,,214210000.0,416160000.0,251840000.0,1723600000.0,100080000.0,7563900000.0,328060000.0,9625700000.0,3999200000.0,489840000.0,683540000.0,552720000.0,17111000.0,2537700000.0,146840000.0,60922000.0,4959900000.0,2211800000.0,887460000.0,,1113800000.0,627720000.0,2235100000.0,113320000.0,3333900000.0,142360000.0,91454000.0,124800000.0,199710000.0,,663370000.0,208560000.0,5509900000.0,,1099100000.0,897610000.0,,3056800000.0,3682300000.0,177110000.0,339810000.0,2968600000.0,314620000.0,203640000.0,37771000000.0,414960000.0,42709000.0,50194000.0,105250000.0,,,1460600000.0,457990000.0,255850000.0,,,371230000.0,785760000.0,147660000.0,806120000.0,752600000.0,131330000.0,2673100000.0,440570000.0,1016700000.0,,766620000.0,22121000000.0,2924300000.0,28024000000.0,274300000.0,568430000.0,,271020000.0,827020000.0,257590000.0,1317000000.0,10165000000.0,134500000.0,400930000.0,1409700000.0,123250000.0,,10014000000.0,4382400000.0,,189000000.0,68578000.0,1166000000.0,11325000000.0,955160000.0,791270000.0,40566000000.0,14241000000.0,1533600000.0,492380000.0,7659800000.0,3542600000.0,810320000.0,223280000.0,826320000.0,424940000.0,4867700000.0,617390000.0,2391900000.0,,95767000.0,488630000.0,1643800000.0,2972100000.0,1185200000.0,127450000.0,27848000000.0,139650000.0,1542700000.0,21880000000.0,34588000.0,3213700000.0,169710000.0,2551300000.0,4531300000.0,,278040000.0,1317900000.0,213370000.0,487990000.0,,,1378000000.0,186490000.0,59668000.0,163120000.0,696410000.0,458070000.0,432130000.0,158080000.0,69943000.0,861960000.0,23615000000.0,1169400000.0,1050500000.0,5013300000.0,1332800000.0,12624000000.0,,1143500000.0,250360000.0,428570000.0,,292910000.0,2129300000.0,,216340000.0,1061400000.0,453020000.0,35484000000.0,1009100000.0,123010000.0,34840000.0,6443800000.0,21451000000.0,,2486300000.0,1268900000.0,1516300000.0,526420000.0,4552900000.0,937550000.0,231730000.0,4523200000.0,3740900000.0,,710370000.0,922290000.0,710330000.0,7031600000.0,,44610000.0,459480000.0,141020000.0,321790000.0,804390000.0,18096000.0,3610700000.0,110520000.0,541170000.0,2428500000.0,3835300000.0,3048800000.0,758090000.0,,1145200000.0,832220000.0,451630000.0,396440000.0,645180000.0,,172740000.0,,2103800000.0,,,426530000.0,150510000.0,,3546700000.0,21179000000.0,602260000.0,31531000.0,411580000.0,7111400000.0,,86381000.0,545690000.0,111200000.0,358770000.0,290380000.0,94995000.0,470420000.0,1176300000.0,2649900000.0,119090000.0,978340000.0,698700000.0,1698500000.0,3731200000.0,455780000.0,125050000.0,5576100000.0,261290000.0,373330000.0,358260000.0,686960000.0,36564000.0,16737000000.0,1267300000.0,,82170000.0,,32136000.0,45755000.0,258310000.0,179330000.0,884370000.0,11154000000.0,,,1156900000.0,1134400000.0,380210000.0,5025500000.0,458430000.0,11244000000.0,393790000.0,23410000000.0,152570000.0,2119100000.0,1390500000.0,157530000.0,1807100000.0,270790000.0,290780000.0,253280000.0,18126000000.0,169950000.0,5230900000.0,703690000.0,286660000.0,,,,251840000.0,12658000.0,160880000.0 +2020_02_13_00_26_Q-Exactive-HF-X-Orbitrap_6070,,,64983000000.0,472240000.0,,,,2537700000.0,1403400000.0,163550000.0,133200000.0,,364170000.0,3086700000.0,238630000.0,307690000.0,,919980000.0,37861000.0,423620000.0,4152800000.0,94567000.0,393980000.0,4285000000.0,925000000.0,2786900000.0,161160000.0,1538400000.0,116900000.0,167760000.0,131680000.0,134720000.0,14057000000.0,,,483470000.0,59447000000.0,323510000.0,11521000000.0,238010000.0,1314500000.0,725200000.0,7590100000.0,2355500000.0,1308100000.0,3403400000.0,305370000.0,382780000.0,,928590000.0,148130000.0,,3359800000.0,1590600000.0,60507000.0,138140000.0,371500000.0,1313700000.0,857230000.0,8014000000.0,259600000.0,377690000.0,,533750000.0,169950000.0,37456000.0,194600000.0,8719000000.0,,2622100000.0,311840000.0,162970000.0,57906000.0,422990000.0,875690000.0,,4388200000.0,597850000.0,193420000.0,6501600000.0,434740000.0,474180000.0,596160000.0,,,414360000.0,162110000.0,179660000.0,171180000.0,106950000.0,125840000.0,52898000.0,288170000.0,429820000.0,,27620000.0,771510000.0,62603000.0,364080000.0,274790000.0,11030000000.0,4201100000.0,2455400000.0,,89960000.0,14442000000.0,,664410000.0,,58098000.0,690830000.0,464760000.0,,,2132500000.0,169080000.0,,1159000000.0,2429300000.0,442430000.0,1608300000.0,1740700000.0,193690000.0,6007900000.0,512980000.0,61891000.0,206990000.0,2517800000.0,35411000.0,1937700000.0,283730000.0,193790000.0,432890000.0,125940000.0,115320000.0,120400000.0,394730000.0,29755000000.0,,71546000.0,3053400000.0,,219890000.0,6808700000.0,95652000.0,,331680000.0,109940000.0,321370000.0,60864000.0,1102000000.0,136490000.0,316720000.0,313660000.0,548200000.0,2023800000.0,688650000.0,290640000.0,1884000000.0,974460000.0,5087700000.0,,1697900000.0,129570000.0,311940000.0,633110000.0,491690000.0,530850000.0,412670000.0,1297000000.0,274750000.0,112110000.0,106620000.0,63214000.0,107530000.0,154880000.0,2645100000.0,494590000.0,1508100000.0,,130700000.0,386340000.0,301860000.0,1821600000.0,115810000.0,6567900000.0,374750000.0,8492100000.0,4265300000.0,349630000.0,805470000.0,639200000.0,236060000.0,3159200000.0,100790000.0,87025000.0,4073500000.0,2663700000.0,960180000.0,,690490000.0,465280000.0,2585900000.0,219010000.0,26630000000.0,199670000.0,103670000.0,331400000.0,297440000.0,127490000.0,875650000.0,193920000.0,5650000000.0,,1043900000.0,1881000000.0,,3680700000.0,3393000000.0,129350000.0,469440000.0,3828000000.0,455210000.0,74455000.0,28502000000.0,358810000.0,,131320000.0,85759000.0,,,1744500000.0,490130000.0,280880000.0,544320000.0,,311930000.0,917030000.0,317500000.0,411830000.0,772370000.0,136100000.0,2509900000.0,460780000.0,1312600000.0,,588980000.0,23811000000.0,2712800000.0,28470000000.0,301940000.0,669750000.0,,264560000.0,882310000.0,332890000.0,1535800000.0,10036000000.0,121670000.0,505620000.0,1277500000.0,91759000.0,12460000.0,9800000000.0,4977800000.0,,209670000.0,424740000.0,1113100000.0,13626000000.0,823990000.0,1132700000.0,42092000000.0,14468000000.0,2577500000.0,375640000.0,7049300000.0,3255700000.0,873830000.0,230270000.0,634460000.0,528760000.0,6205000000.0,915340000.0,2210100000.0,157480000.0,68266000.0,600440000.0,1308500000.0,2880200000.0,636290000.0,131450000.0,30588000000.0,46477000.0,1470500000.0,21472000000.0,,5990700000.0,134840000.0,378950000.0,5282200000.0,,248770000.0,1403400000.0,265680000.0,711320000.0,,,1065000000.0,60518000.0,90794000.0,239450000.0,783400000.0,482420000.0,587970000.0,127930000.0,101560000.0,918020000.0,16690000000.0,1287300000.0,1513800000.0,4523700000.0,1816600000.0,13559000000.0,,818740000.0,167980000.0,487980000.0,,328600000.0,2564200000.0,,307500000.0,965900000.0,250150000.0,38355000000.0,1132500000.0,,,6108900000.0,25166000000.0,,2477100000.0,1163100000.0,1966700000.0,1089900000.0,3879900000.0,727820000.0,306220000.0,4296500000.0,4576800000.0,,784110000.0,1112600000.0,1163400000.0,7970700000.0,,,352780000.0,191250000.0,691000000.0,830850000.0,24422000.0,3246000000.0,221060000.0,752680000.0,2297800000.0,4610400000.0,3404300000.0,684650000.0,,1300400000.0,614700000.0,321190000.0,445710000.0,727500000.0,21224000.0,187780000.0,,1837800000.0,23611000.0,112040000.0,1595100000.0,572390000.0,,4135800000.0,20688000000.0,728390000.0,,417000000.0,9503100000.0,,187470000.0,676950000.0,136160000.0,254210000.0,407340000.0,,338740000.0,1028700000.0,2498100000.0,178880000.0,1017400000.0,1009000000.0,777280000.0,3968400000.0,600110000.0,24047000.0,5758800000.0,292470000.0,330880000.0,504250000.0,693210000.0,,17464000000.0,1896900000.0,,158460000.0,18384000.0,52328000.0,66436000.0,264110000.0,116450000.0,786270000.0,10855000000.0,77351000.0,,1427300000.0,1065200000.0,554810000.0,5632700000.0,700850000.0,14179000000.0,282300000.0,23748000000.0,158290000.0,2150900000.0,1589300000.0,222220000.0,857230000.0,410410000.0,146950000.0,217440000.0,19294000000.0,115500000.0,5084200000.0,921470000.0,213270000.0,56332000.0,,,236370000.0,17131000.0,28695000.0 +2020_02_13_03_11_Q-Exactive-HF-X-Orbitrap_6070,,,67090000000.0,607260000.0,,,,2468300000.0,1375100000.0,137540000.0,143400000.0,,405140000.0,3202900000.0,293920000.0,288920000.0,,983600000.0,76238000.0,405900000.0,4896700000.0,132570000.0,1131700000.0,4864300000.0,994220000.0,2701800000.0,510660000.0,1721100000.0,174550000.0,212990000.0,,213240000.0,14513000000.0,,26727000.0,332750000.0,65575000000.0,361230000.0,10005000000.0,587800000.0,1580600000.0,603630000.0,8419700000.0,2515500000.0,1306100000.0,4017800000.0,387960000.0,278090000.0,2598300000.0,908100000.0,82926000.0,,3153500000.0,1804700000.0,72178000.0,152080000.0,282020000.0,1264100000.0,1144800000.0,8790400000.0,193580000.0,365050000.0,47402000.0,494040000.0,105080000.0,52281000.0,195370000.0,10166000000.0,,3003500000.0,479740000.0,106750000.0,101860000.0,409580000.0,722790000.0,37581000.0,3813000000.0,755440000.0,72127000.0,7121200000.0,782110000.0,609560000.0,800740000.0,,63592000.0,372550000.0,180760000.0,454000000.0,360890000.0,128660000.0,,63478000.0,283490000.0,476980000.0,,37133000.0,1012400000.0,55725000.0,349050000.0,351850000.0,12504000000.0,4011900000.0,2425600000.0,,135230000.0,12980000000.0,91364000.0,771550000.0,,59584000.0,954550000.0,810670000.0,,,86793000.0,219650000.0,,1117200000.0,2374300000.0,718610000.0,1829700000.0,2335800000.0,210260000.0,7113800000.0,436890000.0,72885000.0,,2388400000.0,,1899900000.0,337980000.0,151770000.0,628740000.0,294790000.0,115050000.0,,453870000.0,30347000000.0,,,118190000.0,,250580000.0,6005700000.0,231260000.0,,292430000.0,138960000.0,101500000.0,58904000.0,1319900000.0,166470000.0,321160000.0,379710000.0,942010000.0,2291100000.0,630230000.0,389570000.0,2308500000.0,1076000000.0,5357900000.0,16198000.0,1986600000.0,188760000.0,261720000.0,708270000.0,579810000.0,697160000.0,717020000.0,1535400000.0,401190000.0,,36277000.0,38779000.0,99191000.0,159550000.0,2670300000.0,488370000.0,1613200000.0,,118260000.0,521260000.0,373550000.0,2418300000.0,134730000.0,7126600000.0,279760000.0,9050300000.0,3791600000.0,459950000.0,659860000.0,858000000.0,160620000.0,3805800000.0,144130000.0,45275000.0,5636900000.0,2009100000.0,1014200000.0,,1276500000.0,750320000.0,2573800000.0,128550000.0,31105000000.0,95545000.0,111520000.0,279950000.0,302820000.0,,593350000.0,259950000.0,5274500000.0,,989420000.0,1842700000.0,,3470200000.0,4698600000.0,28951000.0,364530000.0,4167800000.0,665410000.0,222010000.0,31527000000.0,357940000.0,124330000.0,161670000.0,93390000.0,,,1811800000.0,440590000.0,264710000.0,,,344860000.0,1033800000.0,287880000.0,739840000.0,708830000.0,124820000.0,2919400000.0,671260000.0,2422100000.0,,599110000.0,29266000000.0,3140100000.0,29466000000.0,480150000.0,733540000.0,54178000.0,192970000.0,1116500000.0,292230000.0,1708200000.0,10488000000.0,272830000.0,590620000.0,1751400000.0,100250000.0,,10564000000.0,4265300000.0,,225220000.0,43627000.0,1297700000.0,13855000000.0,920440000.0,1202900000.0,41832000000.0,16606000000.0,2336300000.0,520230000.0,8865500000.0,3722600000.0,942130000.0,278780000.0,734980000.0,548390000.0,6716200000.0,821350000.0,1741900000.0,144160000.0,36352000.0,542820000.0,1327400000.0,2115000000.0,908190000.0,152870000.0,31324000000.0,97915000.0,1562700000.0,23460000000.0,,6196700000.0,203340000.0,3676200000.0,5370100000.0,,238130000.0,1614000000.0,289070000.0,861470000.0,,,985140000.0,179240000.0,83610000.0,242050000.0,362030000.0,622710000.0,593320000.0,43743000.0,152290000.0,974940000.0,18748000000.0,1539500000.0,1067700000.0,5235700000.0,1710500000.0,13299000000.0,,726170000.0,223820000.0,397110000.0,,273400000.0,2806000000.0,,280000000.0,1184900000.0,269520000.0,38558000000.0,3106500000.0,,,7223400000.0,51371000000.0,,2516300000.0,1380700000.0,2458000000.0,1065500000.0,4593700000.0,657450000.0,810420000.0,4483800000.0,5310900000.0,,743430000.0,705480000.0,1290600000.0,7273300000.0,,,456500000.0,318050000.0,399440000.0,1141300000.0,15172000.0,5173200000.0,168460000.0,885230000.0,2463000000.0,4659500000.0,4223900000.0,605650000.0,,1506800000.0,778770000.0,378000000.0,478440000.0,710420000.0,156590000.0,221050000.0,,2203800000.0,59944000.0,,259880000.0,457400000.0,,4374500000.0,21292000000.0,811270000.0,,495020000.0,11459000000.0,,201130000.0,615750000.0,147200000.0,,540870000.0,58328000.0,445270000.0,1388700000.0,2752200000.0,199800000.0,791360000.0,1101300000.0,1162100000.0,4772300000.0,431410000.0,111650000.0,5004500000.0,125290000.0,398680000.0,179780000.0,770180000.0,,22653000000.0,2168400000.0,,121410000.0,17654000.0,62138000.0,49240000.0,303550000.0,49965000.0,985110000.0,11854000000.0,80778000.0,,1734700000.0,1469700000.0,677200000.0,5213800000.0,654640000.0,12259000000.0,354580000.0,25825000000.0,153190000.0,2165300000.0,1801900000.0,350060000.0,828820000.0,227900000.0,241080000.0,45290000.0,22527000000.0,141190000.0,6136400000.0,799860000.0,473780000.0,46869000.0,,846620000.0,172480000.0,14830000.0,37496000.0 +2020_02_17_13_55_Q-Exactive-HF-X-Orbitrap_6070,,,33250000000.0,197270000.0,,22099000.0,,898980000.0,717540000.0,180550000.0,53316000.0,,45790000.0,2051900000.0,126280000.0,234280000.0,,473960000.0,,96380000.0,2376200000.0,79288000.0,,2583700000.0,292730000.0,936610000.0,165720000.0,909880000.0,125090000.0,87746000.0,110360000.0,70943000.0,6666100000.0,,,203730000.0,27111000000.0,154120000.0,4755900000.0,322100000.0,726010000.0,248820000.0,3510900000.0,1175300000.0,683300000.0,1709400000.0,217530000.0,232130000.0,1566500000.0,113620000.0,288130000.0,,1365000000.0,296430000.0,59097000.0,21097000.0,224150000.0,1099900000.0,440990000.0,4540600000.0,118490000.0,271240000.0,44879000.0,426310000.0,153260000.0,29403000.0,48219000.0,4952900000.0,,941000000.0,271320000.0,28066000.0,113420000.0,201190000.0,219990000.0,,1809000000.0,228590000.0,151780000.0,3503400000.0,286950000.0,203250000.0,246120000.0,,,179740000.0,112020000.0,34448000.0,212460000.0,,39359000.0,28675000.0,165440000.0,227360000.0,58657000.0,73383000.0,481020000.0,39252000.0,134720000.0,231850000.0,7599500000.0,1841500000.0,923240000.0,,38597000.0,4625900000.0,44990000.0,506400000.0,,90614000.0,586430000.0,232150000.0,,,,98156000.0,,501350000.0,2200300000.0,293880000.0,261660000.0,1007000000.0,94645000.0,3455200000.0,107370000.0,112840000.0,,1153300000.0,,781590000.0,257350000.0,68950000.0,176660000.0,204020000.0,48856000.0,,258960000.0,14265000000.0,,40741000.0,85996000.0,241120000.0,102600000.0,2823900000.0,25322000.0,10865000.0,267680000.0,42427000.0,67895000.0,7670000.0,335340000.0,100070000.0,262750000.0,105380000.0,534400000.0,1023600000.0,457650000.0,126670000.0,1350600000.0,261500000.0,3112000000.0,,684660000.0,194640000.0,32287000.0,330900000.0,175740000.0,346480000.0,321110000.0,357660000.0,314470000.0,37157000.0,95091000.0,,28553000.0,91572000.0,1389600000.0,537300000.0,562370000.0,,117090000.0,273750000.0,144940000.0,907920000.0,33794000.0,3808600000.0,133720000.0,4126200000.0,3683700000.0,235010000.0,374750000.0,253130000.0,155290000.0,1403300000.0,,29669000.0,2034600000.0,705440000.0,400010000.0,640370000.0,224930000.0,424610000.0,1107900000.0,113210000.0,1497900000.0,49614000.0,355210000.0,90142000.0,87339000.0,,452300000.0,139750000.0,2559800000.0,,506230000.0,586570000.0,,1317100000.0,2414900000.0,64195000.0,215930000.0,2295800000.0,156850000.0,45371000.0,19660000000.0,166210000.0,64316000.0,62967000.0,8414400.0,,,842630000.0,221680000.0,99166000.0,,,91596000.0,626460000.0,73218000.0,425730000.0,200830000.0,103960000.0,1369800000.0,135480000.0,456280000.0,,429780000.0,13428000000.0,1388900000.0,13770000000.0,260380000.0,287420000.0,8726400.0,190130000.0,514140000.0,91322000.0,769360000.0,5112300000.0,22240000.0,290900000.0,345310000.0,42792000.0,,3825700000.0,2427300000.0,,87343000.0,195550000.0,335970000.0,6455000000.0,298120000.0,343110000.0,20331000000.0,8019000000.0,688500000.0,265730000.0,3302100000.0,2154600000.0,342180000.0,101170000.0,308420000.0,162670000.0,2780300000.0,1816300000.0,1058800000.0,,,224410000.0,642800000.0,962050000.0,620230000.0,11827000.0,17946000000.0,52107000.0,837290000.0,12784000000.0,,2472800000.0,78420000.0,69021000.0,2943700000.0,,234150000.0,869830000.0,131040000.0,415460000.0,,12075000000.0,291850000.0,160930000.0,67141000.0,50303000.0,227280000.0,438860000.0,242010000.0,62568000.0,43746000.0,596150000.0,7283200000.0,365470000.0,2475200000.0,2536500000.0,651750000.0,7909700000.0,,270650000.0,131480000.0,215980000.0,,164840000.0,44610000.0,,189990000.0,635870000.0,78366000.0,16318000000.0,1286600000.0,92756000.0,59235000.0,3366100000.0,12082000000.0,,2505600000.0,712710000.0,1068100000.0,675760000.0,2724800000.0,298790000.0,392500000.0,1671600000.0,2519500000.0,,410770000.0,345940000.0,672060000.0,4533200000.0,,,294470000.0,110550000.0,215880000.0,383250000.0,22220000.0,3651700000.0,93818000.0,468400000.0,1526500000.0,3857400000.0,1008000000.0,306860000.0,,346420000.0,571240000.0,127030000.0,159300000.0,311240000.0,,334480000.0,436440000.0,780210000.0,,36873000.0,408660000.0,95205000.0,,1888100000.0,10574000000.0,604050000.0,9355200.0,204570000.0,6007800000.0,,,196350000.0,122170000.0,164170000.0,187400000.0,,244590000.0,626770000.0,977360000.0,165200000.0,634420000.0,488410000.0,910350000.0,1586700000.0,186670000.0,91748000.0,2346100000.0,362190000.0,203790000.0,66762000.0,504320000.0,,9885700000.0,606300000.0,,83513000.0,11722000.0,26017000.0,,114170000.0,76167000.0,341930000.0,5178800000.0,59377000.0,,947520000.0,545790000.0,,1634800000.0,198590000.0,4459200000.0,119880000.0,12157000000.0,141210000.0,625800000.0,1104600000.0,177530000.0,1760800000.0,128400000.0,137950000.0,158410000.0,9049700000.0,11424000.0,3748500000.0,619560000.0,,57551000.0,279570000.0,,64708000.0,,98188000.0 +2020_02_18_01_25_Q-Exactive-HF-X-Orbitrap_6070,,,33673000000.0,55309000.0,,28283000.0,,990810000.0,629120000.0,44760000.0,67128000.0,,40202000.0,1183700000.0,206950000.0,194510000.0,,497860000.0,36460000.0,169500000.0,2456300000.0,84651000.0,193100000.0,1878800000.0,282800000.0,954100000.0,93034000.0,1151700000.0,100820000.0,120690000.0,94362000.0,,6035000000.0,,58865000.0,156810000.0,24420000000.0,101650000.0,4120300000.0,203100000.0,501710000.0,140060000.0,3388400000.0,955210000.0,407190000.0,1352700000.0,136650000.0,78504000.0,1127300000.0,568380000.0,70108000.0,,1195100000.0,315730000.0,53364000.0,83636000.0,53321000.0,364800000.0,312020000.0,4448100000.0,126980000.0,108700000.0,,230380000.0,123140000.0,,18740000.0,5599500000.0,15833000.0,928120000.0,244800000.0,44210000.0,38540000.0,226830000.0,310550000.0,,1255000000.0,288020000.0,36359000.0,3261100000.0,257130000.0,121100000.0,291150000.0,,,87191000.0,127640000.0,179090000.0,54969000.0,108270000.0,57429000.0,31577000.0,86331000.0,161820000.0,53993000.0,,451400000.0,,113730000.0,145090000.0,7108100000.0,1510000000.0,957320000.0,,75886000.0,7569300000.0,13117000.0,602050000.0,35080000.0,29577000.0,497170000.0,318860000.0,,,21933000.0,66480000.0,,332380000.0,2202300000.0,286210000.0,412830000.0,653380000.0,82978000.0,3031900000.0,101320000.0,36341000.0,26950000.0,771580000.0,46018000.0,635460000.0,110870000.0,29851000.0,235230000.0,184180000.0,36465000.0,7178200.0,201300000.0,,,39967000.0,49050000.0,329560000.0,32588000.0,3417500000.0,64008000.0,,74257000.0,40294000.0,52904000.0,31203000.0,309390000.0,114360000.0,209900000.0,249700000.0,762260000.0,802820000.0,508220000.0,62317000.0,1384000000.0,198460000.0,2924800000.0,,759850000.0,,,261550000.0,454930000.0,253230000.0,249440000.0,768160000.0,171960000.0,,33878000.0,,43545000.0,102210000.0,1434100000.0,233040000.0,986290000.0,,,172940000.0,202640000.0,796820000.0,138430000.0,2670900000.0,85696000.0,4698300000.0,2232700000.0,171830000.0,133190000.0,222860000.0,200760000.0,1028900000.0,89147000.0,42336000.0,2186100000.0,813600000.0,212470000.0,217960000.0,,277110000.0,1342300000.0,66267000.0,1508600000.0,13705000.0,304590000.0,81560000.0,28064000.0,,183380000.0,102590000.0,2416400000.0,,369460000.0,533910000.0,,759950000.0,1934500000.0,82301000.0,129010000.0,1555000000.0,89197000.0,31213000.0,23159000000.0,91052000.0,27280000.0,9248100.0,13419000.0,,,654040000.0,167480000.0,,776910000.0,,110360000.0,444770000.0,35037000.0,85602000.0,106840000.0,99408000.0,1255600000.0,106630000.0,352370000.0,,274280000.0,11584000000.0,898690000.0,11728000000.0,114830000.0,208360000.0,20289000.0,146930000.0,414860000.0,110370000.0,888930000.0,6710000000.0,61332000.0,258970000.0,207260000.0,32020000.0,,2804900000.0,1873500000.0,46673000.0,30465000.0,182460000.0,446300000.0,5102900000.0,441230000.0,211560000.0,18020000000.0,6118600000.0,609090000.0,138720000.0,3410700000.0,1939400000.0,216750000.0,60098000.0,461370000.0,190370000.0,2228600000.0,638470000.0,621950000.0,46452000.0,31129000.0,191040000.0,722030000.0,1804600000.0,685130000.0,11041000.0,21129000000.0,71411000.0,858910000.0,10277000000.0,,1846500000.0,61208000.0,1618100000.0,2642900000.0,25557000.0,94768000.0,813400000.0,198750000.0,278890000.0,,10407000000.0,329740000.0,26330000.0,25102000.0,103510000.0,93741000.0,209720000.0,250390000.0,41141000.0,39103000.0,424300000.0,7420200000.0,453190000.0,419880000.0,2714800000.0,605630000.0,6675600000.0,,348290000.0,138600000.0,201730000.0,72852000.0,53426000.0,30705000.0,,96642000.0,383140000.0,16418000.0,14045000000.0,873140000.0,,17697000.0,2071400000.0,10652000000.0,,2130900000.0,569800000.0,1145000000.0,484530000.0,2081300000.0,182200000.0,204910000.0,1988300000.0,2899100000.0,,325350000.0,518270000.0,294980000.0,3693900000.0,,42744000.0,195670000.0,50369000.0,81653000.0,489480000.0,22551000.0,2346300000.0,73144000.0,380180000.0,1280500000.0,2995100000.0,1154700000.0,555090000.0,,571830000.0,486560000.0,35153000.0,212030000.0,319900000.0,,74090000.0,,619610000.0,15021000.0,49179000.0,79376000.0,107230000.0,,1857300000.0,7006200000.0,458420000.0,,117120000.0,6544800000.0,,30857000.0,92044000.0,30321000.0,199490000.0,179240000.0,41323000.0,289260000.0,408420000.0,1062800000.0,100210000.0,1177200000.0,407810000.0,835400000.0,1361800000.0,110390000.0,30887000.0,2169300000.0,142870000.0,105830000.0,,289880000.0,,11516000000.0,836820000.0,,21266000.0,,21401000.0,29153000.0,79914000.0,13951000.0,715290000.0,4505900000.0,,,1123000000.0,452510000.0,108670000.0,2100200000.0,229080000.0,5233100000.0,714960000.0,13402000000.0,185880000.0,719050000.0,1188300000.0,89373000.0,1412900000.0,164170000.0,61201000.0,120260000.0,9068100000.0,,3731600000.0,707440000.0,46840000.0,27168000.0,,100640000.0,,,206920000.0 +2020_02_18_18_55_Q-Exactive-HF-X-Orbitrap_6070,,,38552000000.0,405180000.0,,,,1026100000.0,454380000.0,106280000.0,94657000.0,,68494000.0,1087700000.0,202380000.0,,,446910000.0,23843000.0,150050000.0,1944300000.0,40716000.0,,2499500000.0,347370000.0,1241700000.0,125900000.0,345980000.0,237420000.0,40040000.0,27716000.0,59630000.0,5760600000.0,,12085000.0,263900000.0,32063000000.0,89546000.0,4182100000.0,,750970000.0,258380000.0,2886900000.0,1030500000.0,697250000.0,2058600000.0,222240000.0,152920000.0,1668200000.0,137330000.0,186930000.0,,1082500000.0,518440000.0,13549000.0,,231950000.0,569950000.0,556160000.0,5388500000.0,173460000.0,202570000.0,42742000.0,243670000.0,143330000.0,36874000.0,,4152400000.0,,897780000.0,246700000.0,51446000.0,30991000.0,55918000.0,305200000.0,,2046000000.0,130560000.0,117210000.0,3299200000.0,278000000.0,169890000.0,213070000.0,,,771760000.0,70155000.0,73692000.0,387700000.0,33698000.0,28464000.0,24754000.0,147550000.0,95144000.0,70163000.0,102910000.0,321070000.0,848920000.0,259470000.0,40785000.0,3649200000.0,2018900000.0,1115300000.0,,61388000.0,6919600000.0,17117000.0,395200000.0,,60072000.0,362750000.0,381530000.0,,,8700200.0,35084000.0,,576930000.0,1613500000.0,252800000.0,773900000.0,821710000.0,140380000.0,3439000000.0,86446000.0,,21230000.0,1369500000.0,,663590000.0,264210000.0,105060000.0,103450000.0,173760000.0,58242000.0,9195400.0,268400000.0,,,27382000.0,32486000.0,451270000.0,83956000.0,3290600000.0,14945000.0,,181050000.0,49465000.0,142600000.0,10214000.0,301320000.0,50796000.0,87290000.0,86701000.0,803900000.0,1028800000.0,299480000.0,121240000.0,843900000.0,420740000.0,3151000000.0,9794900.0,434610000.0,204090000.0,98028000.0,220250000.0,327470000.0,236630000.0,413380000.0,750240000.0,208070000.0,42137000.0,138090000.0,,78134000.0,,1518600000.0,157620000.0,552810000.0,,154350000.0,237100000.0,74646000.0,974690000.0,36311000.0,4010300000.0,169500000.0,3594200000.0,2407500000.0,245740000.0,356490000.0,222220000.0,77228000.0,1572500000.0,53501000.0,57934000.0,3120000000.0,743380000.0,477430000.0,,455850000.0,489640000.0,770950000.0,,16016000000.0,21511000.0,137440000.0,53823000.0,129270000.0,,124630000.0,83850000.0,2835500000.0,,344090000.0,851400000.0,,1695700000.0,1587900000.0,39517000.0,206420000.0,2066600000.0,78658000.0,57678000.0,18182000000.0,128790000.0,53064000.0,81893000.0,18083000.0,,,689050000.0,179370000.0,126030000.0,272250000.0,,183910000.0,352330000.0,134140000.0,305860000.0,346480000.0,34282000.0,1406800000.0,143100000.0,410730000.0,,212790000.0,9509900000.0,1171300000.0,11882000000.0,284630000.0,182680000.0,13708000.0,215260000.0,362430000.0,257350000.0,1120200000.0,4430400000.0,,189290000.0,622460000.0,18776000.0,,4191200000.0,1078700000.0,17602000.0,39416000.0,323200000.0,399550000.0,5123700000.0,670010000.0,544460000.0,23729000000.0,7108900000.0,743400000.0,291660000.0,3804600000.0,2286200000.0,371910000.0,45266000.0,348660000.0,205130000.0,2852800000.0,620110000.0,553000000.0,67876000.0,42746000.0,168810000.0,506400000.0,670910000.0,425320000.0,30105000.0,19862000000.0,27461000.0,855960000.0,8897800000.0,,2498100000.0,60363000.0,,2585800000.0,21307000.0,88405000.0,740290000.0,171620000.0,252400000.0,,,270520000.0,26898000.0,72600000.0,34521000.0,193680000.0,254710000.0,254890000.0,42145000.0,,520540000.0,5378800000.0,438860000.0,301850000.0,2862700000.0,659410000.0,5184100000.0,,279870000.0,23663000.0,284220000.0,72271000.0,118540000.0,1061900000.0,,135380000.0,441880000.0,171400000.0,15585000000.0,824790000.0,55617000.0,83935000.0,2196500000.0,30254000000.0,,688170000.0,685830000.0,900580000.0,761070000.0,2464600000.0,379770000.0,279790000.0,2073800000.0,1500700000.0,,245970000.0,376940000.0,247940000.0,4634100000.0,,49069000.0,232870000.0,48755000.0,65133000.0,308790000.0,44640000.0,2923000000.0,148660000.0,321490000.0,994230000.0,2455100000.0,1990500000.0,170740000.0,,485490000.0,368240000.0,139870000.0,229920000.0,151770000.0,,148650000.0,,996420000.0,,46712000.0,442720000.0,53375000.0,,1870200000.0,8857900000.0,594700000.0,,224730000.0,4240600000.0,,,254140000.0,38855000.0,84837000.0,74403000.0,47116000.0,296270000.0,466370000.0,1072900000.0,16581000.0,731820000.0,487560000.0,504180000.0,1754700000.0,311180000.0,29103000.0,2075800000.0,172920000.0,177500000.0,53991000.0,637060000.0,,9883800000.0,949410000.0,,72858000.0,,,,143840000.0,,479590000.0,5194400000.0,36475000.0,,640850000.0,455220000.0,110110000.0,1953200000.0,132670000.0,5827900000.0,190700000.0,10729000000.0,118770000.0,611360000.0,811490000.0,158250000.0,469660000.0,192480000.0,,185220000.0,7146500000.0,29265000.0,2976300000.0,208610000.0,146220000.0,20561000.0,,,60018000.0,,93126000.0 +2020_02_28_12_27_Q-Exactive-HF-X-Orbitrap_6070,,,27783000000.0,258140000.0,,13444000.0,,842130000.0,302240000.0,54047000.0,32974000.0,,23629000.0,1525600000.0,94651000.0,83648000.0,,405720000.0,27219000.0,95848000.0,1998100000.0,36108000.0,209600000.0,2156100000.0,226640000.0,917410000.0,63872000.0,462280000.0,68932000.0,98304000.0,46768000.0,58598000.0,4921700000.0,,,209410000.0,22553000000.0,59262000.0,4079500000.0,104900000.0,529270000.0,106780000.0,2273000000.0,780850000.0,452990000.0,1437400000.0,106200000.0,118890000.0,,270880000.0,91650000.0,,702000000.0,310430000.0,14652000.0,62392000.0,143300000.0,360740000.0,363090000.0,3806200000.0,98445000.0,179910000.0,35166000.0,182410000.0,258550000.0,61576000.0,,4020100000.0,,1308200000.0,140500000.0,40038000.0,29098000.0,82506000.0,246060000.0,,1267500000.0,208570000.0,70392000.0,2400700000.0,341200000.0,228500000.0,255610000.0,,,74567000.0,86666000.0,141860000.0,119640000.0,50209000.0,56303000.0,53820000.0,99504000.0,86438000.0,39708000.0,61378000.0,357810000.0,38307000.0,157590000.0,104370000.0,5216700000.0,1393100000.0,910970000.0,,22510000.0,2578700000.0,11463000.0,383350000.0,,68867000.0,310380000.0,212160000.0,,,28881000.0,103030000.0,,321940000.0,555660000.0,210270000.0,442170000.0,549320000.0,78250000.0,1962900000.0,109570000.0,,46895000.0,881350000.0,,538620000.0,45498000.0,60343000.0,158340000.0,81553000.0,32808000.0,,232760000.0,,84210000.0,55366000.0,43752000.0,,134120000.0,2190600000.0,26368000.0,7649300.0,227860000.0,21245000.0,111060000.0,25019000.0,521550000.0,,23612000.0,106420000.0,547750000.0,865200000.0,338990000.0,188310000.0,730620000.0,251580000.0,2058200000.0,,544620000.0,191850000.0,56364000.0,471210000.0,221060000.0,173270000.0,118980000.0,291170000.0,106160000.0,12222000.0,109380000.0,21245000.0,48692000.0,10054000.0,560980000.0,117900000.0,415620000.0,,135500000.0,244080000.0,114330000.0,610410000.0,,3779100000.0,67959000.0,3078400000.0,1275500000.0,121200000.0,346050000.0,147110000.0,13639000.0,1247900000.0,36717000.0,32061000.0,1783400000.0,943920000.0,354790000.0,573360000.0,266950000.0,279840000.0,744310000.0,24165000.0,10115000000.0,50119000.0,154210000.0,99585000.0,73233000.0,,226240000.0,17018000.0,2105000000.0,,274270000.0,569910000.0,,618850000.0,1407300000.0,11350000.0,80738000.0,1584200000.0,159660000.0,102230000.0,16104000000.0,21582000.0,,11097000.0,13295000.0,,,587780000.0,156190000.0,88220000.0,258690000.0,,94794000.0,172750000.0,90949000.0,119170000.0,138890000.0,24494000.0,936030000.0,185730000.0,392440000.0,,224710000.0,8439700000.0,964600000.0,8987800000.0,81422000.0,276460000.0,6663100.0,103430000.0,490880000.0,130850000.0,718230000.0,4460900000.0,78655000.0,161830000.0,409420000.0,10265000.0,,2592800000.0,1935400000.0,,47429000.0,109370000.0,373620000.0,3294100000.0,438210000.0,460670000.0,14982000000.0,4776000000.0,629550000.0,162600000.0,2261200000.0,980110000.0,166590000.0,37151000.0,265730000.0,134690000.0,2542000000.0,227420000.0,438650000.0,,80089000.0,111760000.0,570650000.0,1196300000.0,394670000.0,24744000.0,9260400000.0,75343000.0,574990000.0,8359300000.0,,1433600000.0,53249000.0,109330000.0,1637100000.0,12179000.0,74108000.0,947880000.0,116650000.0,322050000.0,,,330510000.0,33023000.0,32763000.0,31815000.0,183770000.0,82795000.0,226190000.0,28410000.0,38087000.0,260550000.0,8515800000.0,318390000.0,524450000.0,1931900000.0,588890000.0,6056700000.0,1293500000.0,203990000.0,49265000.0,92650000.0,36214000.0,132620000.0,20815000.0,,150030000.0,329540000.0,159390000.0,12229000000.0,771210000.0,62666000.0,39890000.0,1599100000.0,9011500000.0,,1106400000.0,310310000.0,950460000.0,297490000.0,1620500000.0,309420000.0,173640000.0,1764600000.0,1813200000.0,,250310000.0,411620000.0,363440000.0,2191100000.0,,19451000.0,175500000.0,51097000.0,63190000.0,270620000.0,5798800.0,1171200000.0,514100000.0,247060000.0,861040000.0,2642100000.0,1012300000.0,533430000.0,,276910000.0,261750000.0,73519000.0,186590000.0,322030000.0,48973000.0,41131000.0,,678880000.0,,28107000.0,239860000.0,271010000.0,,1471500000.0,9590700000.0,343840000.0,18136000.0,180350000.0,5263000000.0,159700000.0,51186000.0,143070000.0,37632000.0,209780000.0,153790000.0,29257000.0,218400000.0,236930000.0,792820000.0,52895000.0,487460000.0,347630000.0,543910000.0,1002300000.0,175690000.0,30443000.0,1884600000.0,96809000.0,90284000.0,142390000.0,266240000.0,19594000.0,9243500000.0,682110000.0,,30618000.0,6182100.0,,22787000.0,100160000.0,52265000.0,429660000.0,3911600000.0,23308000.0,,378520000.0,474860000.0,111660000.0,1684800000.0,192090000.0,4749300000.0,,9883400000.0,144960000.0,487120000.0,345770000.0,96508000.0,603440000.0,115390000.0,126910000.0,77249000.0,7187300000.0,52421000.0,3021600000.0,450120000.0,116580000.0,,,224480000.0,34193000.0,,162920000.0 +2020_03_01_23_00_Q-Exactive-HF-X-Orbitrap_6070,,,22858000000.0,110320000.0,,12123000.0,,530010000.0,321440000.0,47612000.0,44800000.0,,36145000.0,996450000.0,49919000.0,76941000.0,,176140000.0,11781000.0,71911000.0,1304500000.0,32846000.0,124530000.0,1153900000.0,161720000.0,605740000.0,33491000.0,592780000.0,105070000.0,91843000.0,47812000.0,37641000.0,3613200000.0,,5067500.0,125450000.0,15768000000.0,58911000.0,2566300000.0,84802000.0,416280000.0,91302000.0,1753800000.0,737630000.0,388400000.0,953270000.0,90365000.0,59048000.0,607090000.0,254480000.0,84073000.0,,618830000.0,250880000.0,8923800.0,35659000.0,49389000.0,274250000.0,268450000.0,3218000000.0,43402000.0,163740000.0,25491000.0,79540000.0,37374000.0,35798000.0,40753000.0,2590100000.0,,799240000.0,,22096000.0,,108010000.0,172530000.0,,983580000.0,85444000.0,90203000.0,2041500000.0,119480000.0,88004000.0,151840000.0,7702400.0,,63981000.0,29014000.0,191330000.0,101350000.0,76307000.0,21489000.0,28509000.0,74724000.0,111900000.0,5785100.0,64362000.0,140410000.0,41729000.0,118460000.0,64205000.0,4289900000.0,921610000.0,717610000.0,,23187000.0,2111200000.0,,324750000.0,,33813000.0,170770000.0,209860000.0,,,2980400.0,97193000.0,,268000000.0,603270000.0,137650000.0,295820000.0,421510000.0,77142000.0,1526900000.0,94255000.0,,24001000.0,596880000.0,,506850000.0,76689000.0,24244000.0,122060000.0,72925000.0,36807000.0,14182000.0,90360000.0,,15151000.0,32728000.0,30194000.0,,48320000.0,1865600000.0,3733200.0,,169060000.0,13629000.0,36664000.0,14670000.0,401700000.0,,,56821000.0,286970000.0,509590000.0,151060000.0,43869000.0,743410000.0,271050000.0,1552300000.0,,274670000.0,52172000.0,23529000.0,139050000.0,201100000.0,109510000.0,39198000.0,246690000.0,151980000.0,29152000.0,45950000.0,,55364000.0,,571900000.0,89033000.0,328880000.0,,628730000.0,92027000.0,62497000.0,358740000.0,313740000.0,2801900000.0,65500000.0,2696400000.0,1585900000.0,137330000.0,237030000.0,146360000.0,,770500000.0,7800400.0,4690600.0,1128700000.0,607940000.0,305620000.0,453430000.0,291540000.0,166520000.0,670380000.0,20565000.0,7146200000.0,13058000.0,105440000.0,65050000.0,41509000.0,,164840000.0,17190000.0,922370000.0,,190240000.0,353880000.0,,414290000.0,1265000000.0,,74527000.0,1177800000.0,122900000.0,16040000.0,10431000000.0,59181000.0,,7729800.0,13892000.0,,,493290000.0,128780000.0,52743000.0,,,71241000.0,213350000.0,39814000.0,92856000.0,139360000.0,23239000.0,678780000.0,48649000.0,383810000.0,,166300000.0,6361500000.0,570470000.0,6972200000.0,100760000.0,88460000.0,,94150000.0,468850000.0,136490000.0,436060000.0,4516800000.0,76846000.0,38908000.0,366670000.0,3916300.0,,2210800000.0,1341800000.0,,22784000.0,52045000.0,184230000.0,3179800000.0,296500000.0,362180000.0,12262000000.0,4061700000.0,401090000.0,118790000.0,2273100000.0,910620000.0,320450000.0,36072000.0,188160000.0,77528000.0,2044500000.0,270960000.0,382200000.0,,27352000.0,109370000.0,369610000.0,1338100000.0,426780000.0,40324000.0,10994000000.0,57959000.0,633430000.0,5094600000.0,13242000.0,1485900000.0,30332000.0,170230000.0,1633700000.0,7778600.0,61179000.0,647150000.0,72856000.0,247480000.0,,5230500000.0,293970000.0,31500000.0,68390000.0,56941000.0,175000000.0,58563000.0,175700000.0,38941000.0,39551000.0,112010000.0,4950300000.0,350850000.0,,1157400000.0,330330000.0,4105800000.0,,200290000.0,66828000.0,57649000.0,26211000.0,115860000.0,17256000.0,,49000000.0,295810000.0,123370000.0,10761000000.0,412960000.0,,35371000.0,1321000000.0,6802700000.0,,1135200000.0,268510000.0,634530000.0,335290000.0,1498600000.0,283990000.0,161220000.0,920240000.0,1312600000.0,,130690000.0,321820000.0,281030000.0,1823800000.0,,4474400.0,132960000.0,31166000.0,59041000.0,153640000.0,5956600.0,1642800000.0,9174200.0,224630000.0,786020000.0,1476700000.0,911870000.0,397100000.0,,264800000.0,188680000.0,64741000.0,114770000.0,183580000.0,35185000.0,136530000.0,,340950000.0,,,90600000.0,58133000.0,13204000.0,1011300000.0,4943900000.0,225090000.0,,94581000.0,3964800000.0,,40831000.0,106030000.0,18480000.0,3091000000.0,37084000.0,97980000.0,135770000.0,324740000.0,562400000.0,41942000.0,396130000.0,315100000.0,391810000.0,828850000.0,150450000.0,24440000.0,1641400000.0,122950000.0,60417000.0,83773000.0,286970000.0,6973500.0,6229100000.0,550060000.0,,4877400.0,,,,67877000.0,19032000.0,298330000.0,2751800000.0,13629000.0,,458020000.0,307180000.0,,1926800000.0,93566000.0,3724800000.0,130630000.0,7614700000.0,110820000.0,520620000.0,397640000.0,86495000.0,,78695000.0,80259000.0,58083000.0,5344300000.0,13502000.0,2126400000.0,202280000.0,101580000.0,8761800.0,,137660000.0,25272000.0,5906600.0,52054000.0 +2020_03_06_16_22_Q-Exactive-HF-X-Orbitrap_6070,49169000.0,,22287000000.0,28008000.0,,,4378900000.0,641890000.0,261200000.0,,,,,488830000.0,62155000.0,,,142330000.0,49129000.0,22549000.0,1751600000.0,30768000.0,129950000.0,447620000.0,41992000.0,552320000.0,,288690000.0,5139300.0,84595000.0,98537000.0,27193000.0,2888500000.0,48040000.0,54628000.0,18778000.0,14838000000.0,11629000.0,1202900000.0,139830000.0,16967000.0,24484000.0,1338300000.0,961750000.0,145430000.0,591140000.0,,15892000.0,,,,859760000.0,76129000.0,356300000.0,,,,66744000.0,41242000.0,1630100000.0,24485000.0,46652000.0,7507200.0,115910000.0,9912400.0,116080000.0,,1343000000.0,142920000.0,276280000.0,,,,5630200.0,34752000.0,6718700.0,30130000.0,19798000.0,29471000.0,990660000.0,146700000.0,37572000.0,9535300.0,,73473000.0,,13492000.0,,7966700.0,38291000.0,31416000.0,,,22699000.0,62597000.0,62181000.0,94142000.0,15782000.0,87982000.0,55353000.0,1094600000.0,500250000.0,401270000.0,95171000.0,23717000.0,445510000.0,,85738000.0,,18541000.0,1295300000.0,165540000.0,10648000.0,,6910000.0,66480000.0,,297500000.0,713910000.0,88943000.0,340490000.0,43070000.0,37936000.0,961610000.0,5994600.0,11226000.0,,467330000.0,,395520000.0,17530000.0,,59164000.0,,,21064000.0,45713000.0,,124490000.0,9753300.0,5735900.0,120250000.0,,1094000000.0,,,71736000.0,,37099000.0,7308400.0,219310000.0,,64407000.0,165470000.0,188580000.0,214440000.0,100480000.0,,932280000.0,57610000.0,1394900000.0,,113080000.0,20330000.0,,,30303000.0,131570000.0,103220000.0,59231000.0,189390000.0,251240000.0,9489100.0,,,,523680000.0,106730000.0,343260000.0,37762000.0,97135000.0,8922100.0,32105000.0,145340000.0,7899300.0,730990000.0,48856000.0,1466700000.0,798910000.0,87653000.0,109530000.0,77407000.0,8031600.0,629500000.0,38413000.0,4589400.0,342740000.0,201160000.0,597480000.0,,188450000.0,76737000.0,1080900000.0,19866000.0,1386200000.0,,24091000.0,42955000.0,17299000.0,,80316000.0,,846180000.0,48836000.0,4796500.0,198980000.0,458000000.0,897390000.0,775700000.0,,102350000.0,252910000.0,10365000.0,31375000.0,24047000000.0,49662000.0,,24106000.0,,,24208000.0,332320000.0,60107000.0,,,118390000.0,42110000.0,122820000.0,,5056300.0,11912000.0,,211550000.0,69203000.0,223480000.0,378660000.0,141720000.0,6142500000.0,138940000.0,4204700000.0,23684000.0,,,42369000.0,153710000.0,86781000.0,360320000.0,6267900000.0,,52108000.0,159670000.0,,25493000.0,1589600000.0,253850000.0,11698000.0,16931000.0,18041000.0,5257500.0,1913000000.0,43957000.0,169440000.0,18012000000.0,3042400000.0,135730000.0,4833200.0,1894100000.0,966110000.0,85612000.0,,170310000.0,87487000.0,1568000000.0,175180000.0,44127000.0,,5296100.0,45643000.0,751550000.0,96186000.0,279630000.0,3492700.0,7074100000.0,,67043000.0,1549800000.0,,520270000.0,,,1030900000.0,22557000.0,,191170000.0,54750000.0,96440000.0,419890000.0,,90175000.0,,,,77301000.0,34507000.0,46839000.0,,125210000.0,89972000.0,3582900000.0,154170000.0,2160600000.0,883910000.0,677750000.0,3628600000.0,8977500000.0,,82666000.0,17265000.0,37662000.0,188900000.0,6468400.0,,39604000.0,83802000.0,21899000.0,4518600000.0,370900000.0,,6648100.0,933250000.0,2487700000.0,,1052000000.0,230090000.0,152560000.0,371430000.0,341460000.0,221070000.0,59051000.0,3566200000.0,714010000.0,38346000.0,25295000.0,131800000.0,930450000.0,1726900000.0,,64012000.0,14237000.0,,49939000.0,161480000.0,,854150000.0,31116000.0,48549000.0,1299400000.0,691920000.0,148280000.0,107300000.0,194160000.0,1320600000.0,271040000.0,12949000.0,,99444000.0,4988700.0,31546000.0,,245580000.0,,33190000.0,,205400000.0,,1299200000.0,3357200000.0,214360000.0,5801100.0,21627000.0,3232500000.0,,50846000.0,14389000.0,26296000.0,,32638000.0,75127000.0,17754000.0,134730000.0,56562000.0,32144000.0,125350000.0,23969000.0,244230000.0,338690000.0,11042000.0,31030000.0,356110000.0,125380000.0,64008000.0,104720000.0,51051000.0,,5997600000.0,174640000.0,,,11732000.0,49281000.0,303440000.0,5282200.0,14185000.0,39645000.0,2520600000.0,,67515000.0,89639000.0,33828000.0,,302760000.0,12410000.0,4791200000.0,32941000.0,3290800000.0,7227200.0,305030000.0,159520000.0,28166000.0,1269400000.0,197280000.0,44608000.0,95189000.0,1978500000.0,12440000.0,767360000.0,451280000.0,80948000.0,,,94978000.0,,10702000.0,64538000.0 +2020_03_07_18_15_Q-Exactive-HF-X-Orbitrap_6070,15364000.0,,41904000000.0,22750000.0,,,46626000000.0,1451100000.0,331220000.0,18538000.0,25457000.0,16254000.0,,1127300000.0,,,27635000.0,193250000.0,196130000.0,35070000.0,4305500000.0,50085000.0,571240000.0,1120200000.0,76373000.0,1309000000.0,30877000.0,843500000.0,79688000.0,159870000.0,191010000.0,133610000.0,6068500000.0,238890000.0,129480000.0,178280000.0,27701000000.0,34870000.0,3579600000.0,244190000.0,88433000.0,106140000.0,2362400000.0,1985700000.0,311550000.0,1157000000.0,38080000.0,40901000.0,,238900000.0,39460000.0,3667600000.0,295380000.0,983540000.0,,30761000.0,76051000.0,264140000.0,148570000.0,3638000000.0,51269000.0,71319000.0,49686000.0,192420000.0,35104000.0,234470000.0,28206000.0,3046100000.0,312800000.0,498870000.0,,,,101500000.0,145970000.0,17865000.0,345240000.0,68138000.0,,2190900000.0,318050000.0,64892000.0,50881000.0,,219220000.0,65271000.0,24845000.0,60899000.0,19590000.0,45213000.0,76961000.0,8868700.0,,59629000.0,39114000.0,85836000.0,267180000.0,19774000.0,207720000.0,87252000.0,3532800000.0,970990000.0,615510000.0,188200000.0,21405000.0,701230000.0,20270000.0,158490000.0,,34840000.0,2651300000.0,639370000.0,30542000.0,40582000.0,56103000.0,102410000.0,,748610000.0,835910000.0,189830000.0,611240000.0,127190000.0,122890000.0,2292100000.0,,175400000.0,96607000.0,561480000.0,,772180000.0,54887000.0,,94230000.0,27786000.0,,81481000.0,113590000.0,28161000000.0,462290000.0,7147000.0,23164000.0,290100000.0,,2779100000.0,,,141830000.0,52875000.0,171340000.0,,493400000.0,,103980000.0,273580000.0,504990000.0,791110000.0,354810000.0,14923000.0,1764100000.0,90693000.0,3279400000.0,66633000.0,328870000.0,64961000.0,,145360000.0,73437000.0,341440000.0,312470000.0,286860000.0,594990000.0,924050000.0,36678000.0,,68758000.0,110110000.0,1674900000.0,303760000.0,1028500000.0,211740000.0,287110000.0,54014000.0,74925000.0,256160000.0,18303000.0,2025600000.0,120300000.0,4287500000.0,1790100000.0,227220000.0,233740000.0,140690000.0,,1281000000.0,62576000.0,34248000.0,1075000000.0,543410000.0,829540000.0,,427850000.0,203130000.0,1883100000.0,,3966500000.0,,132860000.0,221160000.0,76048000.0,,151950000.0,11051000.0,3187200000.0,204850000.0,55321000.0,468340000.0,1065600000.0,1496000000.0,1710500000.0,,237940000.0,603920000.0,30704000.0,79783000.0,42697000000.0,134930000.0,,44223000.0,,13452000.0,73363000.0,740030000.0,99487000.0,,,324210000.0,23910000.0,372860000.0,20770000.0,84467000.0,35824000.0,34192000.0,543810000.0,260730000.0,631130000.0,500070000.0,404830000.0,12699000000.0,261210000.0,9716900000.0,76667000.0,,,94410000.0,157020000.0,138690000.0,837010000.0,14455000000.0,,177810000.0,423660000.0,34247000.0,50525000.0,2700300000.0,1319100000.0,51906000.0,27926000.0,140630000.0,44321000.0,3858500000.0,265830000.0,436120000.0,35925000000.0,5760300000.0,331740000.0,39354000.0,3420500000.0,1908600000.0,297920000.0,,674300000.0,208990000.0,3746900000.0,230700000.0,262900000.0,,,108320000.0,1363900000.0,420240000.0,542690000.0,11388000.0,13457000000.0,,143450000.0,3064700000.0,11064000.0,1109700000.0,11450000.0,2123600000.0,2576200000.0,47472000.0,,416650000.0,95073000.0,228520000.0,1189300000.0,12584000000.0,192510000.0,18316000.0,,14717000.0,246140000.0,61503000.0,88751000.0,,320350000.0,224330000.0,8881800000.0,421790000.0,,2431500000.0,1076300000.0,7528100000.0,20664000000.0,38855000.0,70576000.0,5068200.0,62421000.0,507130000.0,35241000.0,,186100000.0,447980000.0,123670000.0,12060000000.0,810030000.0,19166000.0,33634000.0,2219800000.0,5871400000.0,3189900000.0,3211000000.0,493180000.0,388760000.0,730140000.0,569140000.0,523240000.0,118710000.0,8713200000.0,2137000000.0,138880000.0,59192000.0,366740000.0,1487900000.0,3767100000.0,14389000.0,65869000.0,74719000.0,32089000.0,88942000.0,485680000.0,45641000.0,2422800000.0,,251330000.0,3027200000.0,1740800000.0,327650000.0,326370000.0,440950000.0,2973100000.0,528150000.0,86159000.0,60983000.0,248070000.0,49904000.0,83227000.0,,450610000.0,,36426000.0,,489020000.0,26214000.0,1993200000.0,8805600000.0,466640000.0,,29091000.0,7614200000.0,,165230000.0,68872000.0,171730000.0,,124980000.0,187190000.0,92599000.0,379430000.0,246580000.0,,269010000.0,289130000.0,424450000.0,998570000.0,98175000.0,15665000.0,788990000.0,275780000.0,195260000.0,178300000.0,131110000.0,,8974600000.0,717270000.0,63819000.0,,136540000.0,59731000.0,585960000.0,3526600.0,119400000.0,187350000.0,5762000000.0,,,128980000.0,162390000.0,16992000.0,868370000.0,128310000.0,10958000000.0,85450000.0,8383000000.0,30174000.0,535020000.0,675860000.0,15867000.0,3767000000.0,25523000.0,95015000.0,298950000.0,4283800000.0,23191000.0,2055400000.0,704900000.0,295000000.0,,,173500000.0,,39235000.0,168530000.0 +2020_03_11_11_25_Q-Exactive-HF-X-Orbitrap_6070,,,29590000000.0,324970000.0,,19034000.0,,1002800000.0,487230000.0,72803000.0,56164000.0,,103980000.0,1430900000.0,154850000.0,,,582840000.0,31801000.0,175970000.0,2508400000.0,59969000.0,190620000.0,2617300000.0,365590000.0,1437300000.0,106900000.0,628490000.0,194080000.0,84881000.0,98841000.0,80241000.0,7041100000.0,,,245690000.0,26745000000.0,56338000.0,3402100000.0,60975000.0,520830000.0,214800000.0,2525400000.0,1110200000.0,380470000.0,1776200000.0,168690000.0,108440000.0,937910000.0,106670000.0,148680000.0,,1022600000.0,628820000.0,21396000.0,29404000.0,65985000.0,568360000.0,457220000.0,4114000000.0,43475000.0,299030000.0,,284860000.0,135710000.0,,25201000.0,4280800000.0,,1199300000.0,211020000.0,52848000.0,25518000.0,101420000.0,268690000.0,,1878900000.0,263720000.0,217600000.0,3436300000.0,176550000.0,140690000.0,219650000.0,,,487840000.0,119840000.0,156640000.0,608230000.0,91021000.0,48069000.0,22350000.0,106980000.0,135640000.0,52488000.0,17602000.0,582810000.0,27035000.0,206200000.0,78142000.0,4852300000.0,1727800000.0,994850000.0,,35903000.0,2570700000.0,13716000.0,335570000.0,,44950000.0,479710000.0,136330000.0,,,29455000.0,100750000.0,,493840000.0,1397300000.0,214370000.0,525900000.0,826410000.0,92954000.0,2867500000.0,184990000.0,,69046000.0,688580000.0,,788050000.0,99123000.0,46223000.0,186840000.0,181650000.0,51555000.0,12598000.0,161940000.0,10887000000.0,117220000.0,59172000.0,34584000.0,,69574000.0,3017100000.0,53701000.0,,171570000.0,40782000.0,160340000.0,10806000.0,404680000.0,,131480000.0,58011000.0,627620000.0,1152600000.0,370410000.0,108720000.0,940470000.0,420630000.0,2827800000.0,6906200.0,662680000.0,136980000.0,113930000.0,233780000.0,182430000.0,325950000.0,197800000.0,628440000.0,139810000.0,45634000.0,86357000.0,12746000.0,50237000.0,,1031200000.0,129070000.0,545780000.0,,108660000.0,291900000.0,90605000.0,898320000.0,52102000.0,3349400000.0,73435000.0,3945000000.0,2583900000.0,124650000.0,348760000.0,211660000.0,111140000.0,1257000000.0,22720000.0,73263000.0,2187500000.0,1162100000.0,503280000.0,,362770000.0,360340000.0,1014100000.0,29910000.0,10815000000.0,79736000.0,181170000.0,93996000.0,85524000.0,,301780000.0,97503000.0,2842400000.0,,368000000.0,662030000.0,,1997200000.0,1818200000.0,40905000.0,125690000.0,1845400000.0,185390000.0,39803000.0,12501000000.0,121550000.0,,27140000.0,,,,1068800000.0,185010000.0,172860000.0,,,172080000.0,358300000.0,64816000.0,235610000.0,308160000.0,68546000.0,1123500000.0,120480000.0,758420000.0,,262940000.0,8790900000.0,1314300000.0,12039000000.0,274080000.0,182120000.0,11830000.0,209050000.0,341150000.0,217760000.0,792700000.0,5034100000.0,44486000.0,305190000.0,677820000.0,42122000.0,,4106000000.0,1744200000.0,10152000.0,68344000.0,223740000.0,455920000.0,4905700000.0,387130000.0,664980000.0,19067000000.0,7085000000.0,609140000.0,234410000.0,4029200000.0,1681000000.0,260880000.0,75148000.0,269100000.0,234900000.0,2947700000.0,682250000.0,833740000.0,60467000.0,,151770000.0,670740000.0,905730000.0,601550000.0,29601000.0,12364000000.0,23426000.0,760010000.0,8425200000.0,,1419800000.0,95950000.0,39182000.0,2222700000.0,,75337000.0,949780000.0,271260000.0,344660000.0,,10918000000.0,391020000.0,69587000.0,40943000.0,79607000.0,272560000.0,292590000.0,309780000.0,104770000.0,42342000.0,433820000.0,10822000000.0,476700000.0,,2319500000.0,618010000.0,6730700000.0,,295940000.0,51895000.0,230560000.0,13278000.0,76289000.0,20579000.0,,190680000.0,396940000.0,192800000.0,16565000000.0,786160000.0,42563000.0,57581000.0,3124800000.0,11013000000.0,,1298700000.0,480330000.0,1509100000.0,232040000.0,1687300000.0,445820000.0,234550000.0,2248500000.0,2985100000.0,,278230000.0,333840000.0,262620000.0,3661500000.0,,,180830000.0,86316000.0,153080000.0,368930000.0,,2602900000.0,106310000.0,287160000.0,1038000000.0,1891100000.0,1600000000.0,394110000.0,,607300000.0,72268000.0,101340000.0,115640000.0,276940000.0,,156560000.0,185390000.0,773600000.0,272870000.0,45854000.0,145670000.0,202480000.0,,2052900000.0,8413400000.0,444020000.0,,179360000.0,5800300000.0,,,219620000.0,75092000.0,158490000.0,118560000.0,36629000.0,179590000.0,534180000.0,1076900000.0,51649000.0,539870000.0,411950000.0,666950000.0,1643900000.0,236630000.0,53094000.0,2857500000.0,93612000.0,109270000.0,141250000.0,442550000.0,,10776000000.0,552660000.0,,53102000.0,,30445000.0,8857600.0,110400000.0,23830000.0,325370000.0,4907500000.0,17135000.0,,379530000.0,466860000.0,150620000.0,2441500000.0,309390000.0,5009700000.0,224970000.0,10960000000.0,182040000.0,1046700000.0,685870000.0,217120000.0,375850000.0,124900000.0,66334000.0,100440000.0,8250200000.0,12288000.0,3056800000.0,231790000.0,166110000.0,19885000.0,,441860000.0,108630000.0,,67717000.0 +2020_05_04_11_39_Q-Exactive-HF-X-Orbitrap_6070,,,17890000000.0,103260000.0,,6228100.0,,310920000.0,295900000.0,16157000.0,13878000.0,,6079100.0,719960000.0,30899000.0,50947000.0,,150340000.0,4683100.0,59424000.0,985540000.0,6662600.0,143970000.0,999580000.0,92158000.0,455020000.0,23517000.0,348330000.0,51970000.0,64436000.0,408070000.0,28656000.0,2688100000.0,,,60479000.0,11688000000.0,76474000.0,1726600000.0,136110000.0,252270000.0,86289000.0,1532700000.0,379370000.0,201810000.0,596000000.0,67762000.0,52089000.0,518330000.0,11560000.0,57068000.0,,414010000.0,216080000.0,8650400.0,23444000.0,67247000.0,153900000.0,248640000.0,1799400000.0,29101000.0,124310000.0,,146240000.0,131210000.0,,,2311100000.0,,317740000.0,77490000.0,9977600.0,,86542000.0,117670000.0,,525940000.0,107510000.0,46981000.0,1392800000.0,82044000.0,64854000.0,140380000.0,,,47070000.0,52367000.0,94252000.0,50593000.0,51441000.0,20656000.0,8194800.0,62340000.0,65564000.0,7060300.0,21812000.0,220620000.0,12040000.0,110360000.0,39319000.0,3084200000.0,837610000.0,383430000.0,,8636700.0,1530700000.0,4207700.0,254360000.0,,34755000.0,146430000.0,90670000.0,,,,48067000.0,,183560000.0,662870000.0,62730000.0,146230000.0,301880000.0,13343000.0,1135600000.0,91469000.0,,23461000.0,324460000.0,23352000.0,270040000.0,110170000.0,10652000.0,52351000.0,70122000.0,17953000.0,,96469000.0,6268100000.0,32341000.0,23897000.0,5249800.0,72143000.0,74956000.0,1278300000.0,3711200.0,,114820000.0,,328310000.0,2348600.0,254800000.0,,96409000.0,69087000.0,183920000.0,321120000.0,130220000.0,34071000.0,326620000.0,181750000.0,1100000000.0,,296930000.0,55361000.0,17886000.0,76461000.0,101420000.0,98898000.0,128000000.0,306910000.0,129780000.0,37226000.0,30089000.0,5065700.0,11996000.0,,363580000.0,77316000.0,293950000.0,,64902000.0,80899000.0,39459000.0,468370000.0,10810000.0,1705800000.0,41203000.0,2101600000.0,830350000.0,31707000.0,223360000.0,96738000.0,10946000.0,459190000.0,8599300.0,8029000.0,792610000.0,412540000.0,191360000.0,,158410000.0,132670000.0,407960000.0,,5493900000.0,53578000.0,86552000.0,22023000.0,52555000.0,,106990000.0,22092000.0,968340000.0,,178850000.0,273950000.0,,457900000.0,714770000.0,29676000.0,43148000.0,789550000.0,94025000.0,35540000.0,5927900000.0,24935000.0,2553200.0,12236000.0,4192700.0,,,437080000.0,39770000.0,24430000.0,,,5813900.0,56649000.0,31637000.0,132750000.0,101800000.0,24570000.0,414380000.0,17634000.0,256610000.0,,89196000.0,3936800000.0,707390000.0,5114300000.0,51277000.0,55154000.0,7029500.0,65553000.0,271280000.0,63863000.0,287660000.0,2787300000.0,25844000.0,67955000.0,288480000.0,10089000.0,,1322200000.0,1215500000.0,,21459000.0,41592000.0,172150000.0,1876300000.0,164740000.0,190990000.0,8922300000.0,3251700000.0,271170000.0,156550000.0,1249500000.0,683040000.0,61546000.0,27288000.0,99829000.0,46290000.0,1346700000.0,180220000.0,358750000.0,24182000.0,4996300.0,60402000.0,331460000.0,817950000.0,244620000.0,6155000.0,8111200000.0,21133000.0,322500000.0,4548600000.0,,1039800000.0,8527900.0,102010000.0,910970000.0,,30269000.0,405780000.0,37276000.0,72656000.0,,4088300000.0,150830000.0,17371000.0,5000800.0,11634000.0,76613000.0,99380000.0,81316000.0,13988000.0,23890000.0,99434000.0,4802400000.0,162480000.0,,1030400000.0,280660000.0,4107100000.0,,115240000.0,60984000.0,45133000.0,,51018000.0,,,80937000.0,232270000.0,39519000.0,6503400000.0,526470000.0,58292000.0,17831000.0,1108500000.0,10790000000.0,,634340000.0,249190000.0,377200000.0,171760000.0,923380000.0,108740000.0,89590000.0,1016700000.0,1066700000.0,,71286000.0,208330000.0,174400000.0,1237300000.0,,12553000.0,96703000.0,16662000.0,43968000.0,92343000.0,,1234600000.0,85605000.0,119650000.0,701070000.0,1989900000.0,437960000.0,348640000.0,,186730000.0,146440000.0,107220000.0,67337000.0,215430000.0,19063000.0,121130000.0,,303290000.0,167040000.0,16989000.0,64633000.0,103510000.0,,757010000.0,5610600000.0,194100000.0,4153800.0,62789000.0,3013600000.0,,23976000.0,54571000.0,3784600.0,102590000.0,104500000.0,14768000.0,253280000.0,351260000.0,346140000.0,25462000.0,239260000.0,117150000.0,263120000.0,479230000.0,59178000.0,27094000.0,1139000000.0,33871000.0,17727000.0,78026000.0,82749000.0,6723900.0,4490400000.0,295670000.0,,27053000.0,,,,93127000.0,25539000.0,241890000.0,2008900000.0,10272000.0,,417220000.0,251750000.0,36718000.0,1001000000.0,135930000.0,2859500000.0,46105000.0,5301400000.0,48869000.0,214130000.0,322720000.0,41305000.0,,100320000.0,26283000.0,45753000.0,4865300000.0,4377200.0,1350000000.0,263190000.0,50265000.0,5262300.0,,,14718000.0,,81791000.0 +2020_05_12_15_13_Q-Exactive-HF-X-Orbitrap_6070,,,16591000000.0,96716000.0,,,,428460000.0,272290000.0,15842000.0,34481000.0,,28803000.0,644800000.0,38851000.0,20525000.0,,98248000.0,11352000.0,52009000.0,909670000.0,11837000.0,29404000.0,801720000.0,108980000.0,559350000.0,33245000.0,226680000.0,44929000.0,38334000.0,35712000.0,33487000.0,2635200000.0,,,100590000.0,12768000000.0,35481000.0,1978200000.0,,277570000.0,50772000.0,899080000.0,716560000.0,205900000.0,637150000.0,73619000.0,68091000.0,521250000.0,57128000.0,31495000.0,,388700000.0,262600000.0,13960000.0,12670000.0,35334000.0,191510000.0,225280000.0,1761400000.0,32163000.0,142720000.0,9876500.0,102210000.0,19440000.0,10314000.0,12170000.0,1743500000.0,,629060000.0,126110000.0,6785400.0,,64400000.0,136010000.0,,606220000.0,97822000.0,,1251700000.0,161370000.0,77773000.0,88114000.0,,,37536000.0,65652000.0,88943000.0,212320000.0,46541000.0,,3418900.0,41500000.0,30918000.0,25483000.0,11714000.0,283970000.0,,69358000.0,65933000.0,1980700000.0,707920000.0,381200000.0,,11228000.0,2008700000.0,4231500.0,142290000.0,,7731400.0,240130000.0,97550000.0,,,2470900.0,55123000.0,,277970000.0,548300000.0,67450000.0,238140000.0,312190000.0,62901000.0,1040000000.0,71047000.0,14390000.0,20666000.0,361590000.0,9821400.0,328160000.0,93602000.0,10464000.0,72979000.0,69750000.0,10967000.0,,108720000.0,,25138000.0,35932000.0,12297000.0,134960000.0,64122000.0,1106400000.0,19096000.0,,119170000.0,4897800.0,13514000.0,,141440000.0,16206000.0,74136000.0,85320000.0,182200000.0,425420000.0,190330000.0,31938000.0,358200000.0,155990000.0,1028600000.0,,262870000.0,50369000.0,39940000.0,137080000.0,138310000.0,101290000.0,138770000.0,293780000.0,55237000.0,10619000.0,67044000.0,11359000.0,16746000.0,,437930000.0,49927000.0,260140000.0,,76744000.0,89147000.0,32561000.0,224390000.0,23634000.0,1802700000.0,42419000.0,1682700000.0,826270000.0,44522000.0,163180000.0,99680000.0,6973500.0,532360000.0,3833400.0,,891590000.0,441280000.0,163390000.0,,178200000.0,119050000.0,424530000.0,13397000.0,5590900000.0,21364000.0,67997000.0,50825000.0,50221000.0,,72227000.0,15609000.0,1023500000.0,,190400000.0,268060000.0,,543590000.0,851410000.0,15167000.0,121600000.0,718780000.0,113410000.0,11333000.0,6096300000.0,42051000.0,,18292000.0,,,,315390000.0,66540000.0,39868000.0,,,46669000.0,58340000.0,31159000.0,118430000.0,123800000.0,21085000.0,685780000.0,62358000.0,205930000.0,,141430000.0,4405100000.0,555820000.0,6080200000.0,113550000.0,115350000.0,5028100.0,58211000.0,362320000.0,57735000.0,326640000.0,2745500000.0,38487000.0,73634000.0,161970000.0,132960000.0,,1599900000.0,942130000.0,,13833000.0,47909000.0,192630000.0,2040500000.0,133800000.0,347740000.0,9105900000.0,2984200000.0,313280000.0,80398000.0,1557300000.0,719560000.0,105650000.0,34094000.0,82826000.0,99644000.0,1247300000.0,197740000.0,309960000.0,27005000.0,,84435000.0,512850000.0,743790000.0,307240000.0,,7944200000.0,19103000.0,314740000.0,4335300000.0,,742490000.0,27297000.0,620670000.0,1130700000.0,5483200.0,25723000.0,329770000.0,19160000.0,96243000.0,,,157350000.0,31930000.0,23493000.0,13982000.0,119140000.0,383880000.0,118200000.0,52849000.0,29272000.0,126260000.0,4578400000.0,199490000.0,,974240000.0,301910000.0,2395700000.0,,84193000.0,11424000.0,84982000.0,46550000.0,42717000.0,335550000.0,,19020000.0,186540000.0,95778000.0,6437400000.0,280600000.0,17309000.0,7716400.0,779870000.0,4302800000.0,656150000.0,344920000.0,175480000.0,420430000.0,164980000.0,827000000.0,157880000.0,169940000.0,1057900000.0,992170000.0,,70869000.0,167520000.0,264990000.0,1319700000.0,,6207500.0,85628000.0,21433000.0,55892000.0,176450000.0,,1179000000.0,57531000.0,95368000.0,493030000.0,1396900000.0,532350000.0,125990000.0,,238710000.0,138950000.0,110680000.0,69783000.0,168400000.0,,76798000.0,,266730000.0,8874700.0,18475000.0,251500000.0,158920000.0,,411350000.0,5350200000.0,239990000.0,11961000.0,54468000.0,3038500000.0,,36278000.0,67568000.0,41771000.0,71304000.0,69607000.0,14512000.0,104240000.0,172760000.0,445530000.0,67560000.0,215600000.0,154360000.0,278700000.0,545180000.0,82311000.0,25911000.0,1024400000.0,32351000.0,45562000.0,17884000.0,95088000.0,,5145700000.0,205610000.0,,14538000.0,,7077000.0,10145000.0,76581000.0,16879000.0,182590000.0,2134700000.0,,,198480000.0,173640000.0,61938000.0,1084100000.0,129550000.0,2326200000.0,73656000.0,4703200000.0,22950000.0,195720000.0,159160000.0,11202000.0,182600000.0,48162000.0,50845000.0,36287000.0,3665500000.0,27555000.0,1508000000.0,97197000.0,89777000.0,,,,11409000.0,,79798000.0 +2020_05_12_18_10_Q-Exactive-HF-X-Orbitrap_6070,,,13574000000.0,81945000.0,,8947100.0,,349500000.0,201790000.0,13148000.0,10139000.0,,16720000.0,571550000.0,23115000.0,,,74087000.0,9532200.0,45054000.0,613130000.0,10547000.0,,676630000.0,72783000.0,452190000.0,39405000.0,170520000.0,55252000.0,62915000.0,13771000.0,29088000.0,2235600000.0,,,47922000.0,9915400000.0,17708000.0,1546800000.0,58439000.0,234800000.0,55253000.0,1241900000.0,333580000.0,160530000.0,569250000.0,62461000.0,68911000.0,431730000.0,33864000.0,43275000.0,,326010000.0,186600000.0,,33228000.0,53821000.0,145000000.0,168210000.0,1726800000.0,23720000.0,85780000.0,2775600.0,103430000.0,124610000.0,,13915000.0,1625800000.0,,343800000.0,60807000.0,12115000.0,14481000.0,46794000.0,125470000.0,,460450000.0,80830000.0,26682000.0,1025800000.0,55282000.0,86754000.0,84597000.0,,,61030000.0,53499000.0,18267000.0,155210000.0,25468000.0,9903400.0,3117500.0,21778000.0,21293000.0,26788000.0,18050000.0,181120000.0,11831000.0,72949000.0,34778000.0,2132400000.0,449020000.0,313250000.0,,20835000.0,1957000000.0,,147570000.0,,23590000.0,121450000.0,125770000.0,,,6445100.0,48327000.0,,108780000.0,258260000.0,74604000.0,200950000.0,252390000.0,33274000.0,1064600000.0,39472000.0,,26359000.0,263190000.0,4020800.0,290770000.0,61484000.0,,69328000.0,55473000.0,12110000.0,,71400000.0,3766200000.0,27506000.0,9788000.0,16274000.0,119590000.0,73177000.0,1029100000.0,3992400.0,4914300.0,38772000.0,8361500.0,10995000.0,,149770000.0,,31966000.0,33511000.0,159080000.0,337950000.0,129630000.0,41805000.0,315230000.0,93989000.0,955850000.0,,248400000.0,40577000.0,22011000.0,88054000.0,82719000.0,58294000.0,70461000.0,122100000.0,30124000.0,9399000.0,44487000.0,,9163200.0,125800000.0,328990000.0,79461000.0,224260000.0,,37494000.0,65198000.0,61936000.0,196100000.0,10220000.0,1422600000.0,38186000.0,1513100000.0,873500000.0,31061000.0,91842000.0,75898000.0,31023000.0,468220000.0,3625900.0,,705370000.0,451690000.0,203200000.0,,184450000.0,158620000.0,355510000.0,10592000.0,5161200000.0,10654000.0,71952000.0,55242000.0,57950000.0,,94929000.0,27111000.0,916780000.0,,132020000.0,222230000.0,,410340000.0,695460000.0,9767100.0,73644000.0,655400000.0,98813000.0,32079000.0,4692800000.0,22612000.0,,21567000.0,,,,854680000.0,39122000.0,35273000.0,99637000.0,,44797000.0,85486000.0,20587000.0,72008000.0,116010000.0,18554000.0,436360000.0,21142000.0,181220000.0,,88071000.0,3910200000.0,465890000.0,4335100000.0,55545000.0,83932000.0,4620400.0,63183000.0,110640000.0,41768000.0,276750000.0,1994100000.0,25881000.0,54433000.0,250960000.0,3907000.0,,1282700000.0,731500000.0,3682200.0,3558000.0,35967000.0,129260000.0,1728500000.0,228270000.0,281510000.0,6548100000.0,2577300000.0,255110000.0,45596000.0,1327200000.0,497650000.0,75224000.0,16075000.0,95788000.0,31884000.0,1086500000.0,157700000.0,346340000.0,22549000.0,5218700.0,60412000.0,210930000.0,332790000.0,177120000.0,8921700.0,4688200000.0,11047000.0,237040000.0,4177700000.0,,781530000.0,30543000.0,547230000.0,1091400000.0,5121000.0,22410000.0,392190000.0,41547000.0,73055000.0,,,88248000.0,37794000.0,21375000.0,19377000.0,46486000.0,57982000.0,91010000.0,23855000.0,10797000.0,96507000.0,4468100000.0,110170000.0,,803040000.0,172110000.0,1766800000.0,,57413000.0,22603000.0,44331000.0,3179100.0,48857000.0,10990000.0,,68806000.0,168870000.0,52867000.0,5561300000.0,202800000.0,15159000.0,10983000.0,953410000.0,9764700000.0,364840000.0,493470000.0,128760000.0,487950000.0,247100000.0,597090000.0,85238000.0,30569000.0,626140000.0,530440000.0,,89775000.0,169660000.0,150800000.0,1295200000.0,,8805100.0,76604000.0,15211000.0,27025000.0,189680000.0,2050100.0,994700000.0,40731000.0,69034000.0,486740000.0,981310000.0,544070000.0,163390000.0,,209300000.0,137310000.0,46176000.0,86113000.0,44706000.0,9296700.0,56024000.0,,218520000.0,,12576000.0,186840000.0,94458000.0,,431780000.0,3770800000.0,184510000.0,12582000.0,65050000.0,1710800000.0,,8698600.0,71677000.0,,68992000.0,63830000.0,41014000.0,94485000.0,296820000.0,350390000.0,17120000.0,234720000.0,179710000.0,217500000.0,409590000.0,75092000.0,23969000.0,788210000.0,25606000.0,42835000.0,60795000.0,91136000.0,8498100.0,3961900000.0,187910000.0,,16784000.0,,4154200.0,4125100.0,134900000.0,18192000.0,137880000.0,1634100000.0,9644600.0,,277290000.0,197470000.0,43665000.0,809260000.0,110450000.0,1738400000.0,58905000.0,3037100000.0,15789000.0,219720000.0,224170000.0,39507000.0,,72754000.0,32789000.0,39297000.0,2462000000.0,3712900.0,1256300000.0,89459000.0,69273000.0,,,55893000.0,12344000.0,,27874000.0 +2020_05_12_21_07_Q-Exactive-HF-X-Orbitrap_6070,,,13667000000.0,130070000.0,,,,417370000.0,252400000.0,14019000.0,15123000.0,,26969000.0,478130000.0,30497000.0,32554000.0,,150930000.0,10514000.0,45720000.0,853580000.0,,113640000.0,823300000.0,62257000.0,465740000.0,21671000.0,188090000.0,20349000.0,31086000.0,186510000.0,37392000.0,2340700000.0,,,78207000.0,9970500000.0,43252000.0,1597500000.0,,213640000.0,44619000.0,1301500000.0,553850000.0,177370000.0,540870000.0,73804000.0,56739000.0,505770000.0,26871000.0,51547000.0,,579590000.0,228290000.0,20208000.0,21876000.0,40846000.0,204150000.0,221130000.0,1421500000.0,56320000.0,131380000.0,,77373000.0,66939000.0,,9010100.0,1787100000.0,,530380000.0,65455000.0,11475000.0,4639000.0,61983000.0,105670000.0,,460330000.0,60593000.0,19366000.0,984900000.0,185040000.0,97945000.0,111570000.0,,,51662000.0,46040000.0,39307000.0,160900000.0,22800000.0,6661200.0,13621000.0,23580000.0,42739000.0,25311000.0,35650000.0,197950000.0,325030000.0,86418000.0,51493000.0,3812400000.0,711680000.0,307430000.0,,8520900.0,1476500000.0,4343200.0,141080000.0,,7516500.0,114400000.0,89018000.0,,,6422700.0,37155000.0,,188670000.0,492710000.0,148400000.0,173020000.0,213660000.0,31701000.0,2652500000.0,54893000.0,,11568000.0,334200000.0,7684800.0,279040000.0,80120000.0,7347800.0,96412000.0,36013000.0,25648000.0,,85573000.0,5919800000.0,20889000.0,14095000.0,8912600.0,120640000.0,50483000.0,1164400000.0,,3823800.0,91221000.0,,7732700.0,5587500.0,135690000.0,21647000.0,49975000.0,77482000.0,161020000.0,428050000.0,125710000.0,46763000.0,421020000.0,123010000.0,993950000.0,,291980000.0,39044000.0,19167000.0,97049000.0,118510000.0,80616000.0,69880000.0,200630000.0,67946000.0,,43039000.0,6895900.0,18414000.0,32333000.0,343950000.0,63708000.0,239270000.0,,51219000.0,71358000.0,19343000.0,275790000.0,8958100.0,1460200000.0,28595000.0,1585300000.0,691420000.0,56725000.0,152950000.0,130540000.0,11433000.0,435970000.0,2943400.0,5459200.0,799020000.0,517100000.0,197700000.0,,157930000.0,118120000.0,329380000.0,5203100.0,5617500000.0,48264000.0,62164000.0,67134000.0,39744000.0,,92612000.0,15447000.0,785520000.0,,180400000.0,207360000.0,,445520000.0,744150000.0,13116000.0,78016000.0,695140000.0,90953000.0,21589000.0,5013500000.0,25185000.0,,10202000.0,5842600.0,,,218110000.0,116370000.0,37026000.0,423100000.0,,15935000.0,85973000.0,27103000.0,96714000.0,101700000.0,,417540000.0,24405000.0,244300000.0,,86308000.0,3815400000.0,489620000.0,4615000000.0,89121000.0,83356000.0,2164300.0,69480000.0,251480000.0,52888000.0,267950000.0,2160800000.0,41010000.0,69210000.0,198870000.0,104050000.0,,1241800000.0,827220000.0,5770500.0,18508000.0,41010000.0,142530000.0,1865900000.0,173640000.0,253310000.0,7395000000.0,2876500000.0,262460000.0,21389000.0,1317000000.0,622820000.0,61245000.0,22542000.0,62445000.0,120370000.0,1231500000.0,148030000.0,233240000.0,26827000.0,,81494000.0,410420000.0,543540000.0,193090000.0,5507100.0,6245400000.0,20489000.0,291580000.0,3661300000.0,,565580000.0,28821000.0,90669000.0,1026600000.0,5237700.0,20928000.0,347330000.0,35115000.0,69899000.0,,3863700000.0,142730000.0,15439000.0,19438000.0,36424000.0,85049000.0,322760000.0,102860000.0,31174000.0,13305000.0,99050000.0,4163300000.0,180520000.0,,761270000.0,239190000.0,2912600000.0,,89110000.0,45193000.0,79711000.0,18328000.0,48627000.0,8344600.0,,16199000.0,130610000.0,50707000.0,5408600000.0,254950000.0,18858000.0,5956600.0,679230000.0,3637800000.0,,362430000.0,159960000.0,316580000.0,163890000.0,678350000.0,159400000.0,17116000.0,853810000.0,1045000000.0,,77634000.0,190260000.0,253760000.0,1185400000.0,,10777000.0,100060000.0,24976000.0,44627000.0,170170000.0,,1037500000.0,40894000.0,55282000.0,480710000.0,1418800000.0,417280000.0,289390000.0,,201550000.0,65350000.0,37362000.0,79630000.0,128450000.0,4655400.0,50046000.0,,246520000.0,11235000.0,14241000.0,178410000.0,72884000.0,,565120000.0,4319700000.0,185340000.0,7947500.0,86534000.0,2070400000.0,,23335000.0,77834000.0,16820000.0,74121000.0,75925000.0,37118000.0,120850000.0,144920000.0,324410000.0,35808000.0,199070000.0,162800000.0,194970000.0,492660000.0,55248000.0,8099200.0,965750000.0,38605000.0,54219000.0,18623000.0,51276000.0,6320400.0,3598100000.0,180190000.0,,27666000.0,,3681000.0,4592500.0,32144000.0,22662000.0,150790000.0,1629200000.0,7170400.0,,166560000.0,206050000.0,48303000.0,714340000.0,111290000.0,1972300000.0,37114000.0,4976900000.0,51939000.0,153500000.0,272850000.0,45332000.0,151830000.0,45344000.0,22028000.0,35678000.0,3839900000.0,12815000.0,1450400000.0,165110000.0,99792000.0,6617600.0,,,9642400.0,,54427000.0 +2020_05_14_14_46_Q-Exactive-HF-X-Orbitrap_6070,,,20792000000.0,52399000.0,,,,518990000.0,314360000.0,26689000.0,27916000.0,,38771000.0,780360000.0,61030000.0,14420000.0,,171340000.0,7914700.0,59928000.0,852580000.0,2942000.0,101430000.0,1240300000.0,118740000.0,532210000.0,33596000.0,414360000.0,47416000.0,44258000.0,62555000.0,58456000.0,2939900000.0,,,96869000.0,13505000000.0,28977000.0,2107300000.0,,162590000.0,82157000.0,1733600000.0,505740000.0,253180000.0,652760000.0,44210000.0,92758000.0,,54046000.0,25218000.0,,491300000.0,215380000.0,,7698100.0,48935000.0,162610000.0,195550000.0,1742700000.0,33581000.0,77584000.0,2653700.0,163540000.0,105830000.0,7289800.0,,2242900000.0,,406690000.0,153730000.0,15665000.0,,79468000.0,319700000.0,3181600.0,591700000.0,112780000.0,116100000.0,1132200000.0,117100000.0,73886000.0,137670000.0,,,66887000.0,36491000.0,37179000.0,260150000.0,37140000.0,,7211000.0,45510000.0,74415000.0,7565200.0,35868000.0,108340000.0,11841000.0,84780000.0,51668000.0,2914700000.0,985960000.0,453010000.0,,14612000.0,2629800000.0,,224420000.0,,11948000.0,182830000.0,40521000.0,,,,46477000.0,,226090000.0,657720000.0,125550000.0,183850000.0,259280000.0,18964000.0,1228900000.0,65759000.0,,,381090000.0,,316860000.0,30686000.0,25706000.0,69061000.0,81794000.0,26710000.0,,94133000.0,,,,8895900.0,,60810000.0,1296300000.0,30819000.0,4880900.0,124390000.0,,49243000.0,,242420000.0,,32735000.0,105820000.0,369980000.0,463170000.0,156810000.0,6423900.0,519580000.0,161410000.0,1583200000.0,,336210000.0,194560000.0,19068000.0,116280000.0,108180000.0,114380000.0,111050000.0,374910000.0,83817000.0,41725000.0,58588000.0,,29082000.0,,473580000.0,46062000.0,242220000.0,,77915000.0,119180000.0,36923000.0,338410000.0,,1815500000.0,67831000.0,2021800000.0,784780000.0,86198000.0,140930000.0,141640000.0,47737000.0,633770000.0,28404000.0,14048000.0,1016000000.0,424420000.0,185700000.0,,,212920000.0,423680000.0,20504000.0,8294100000.0,13500000.0,94545000.0,53842000.0,26346000.0,,78131000.0,13405000.0,1113300000.0,,136550000.0,206510000.0,,607200000.0,1126700000.0,19757000.0,57897000.0,1056400000.0,123210000.0,45505000.0,8157900000.0,57434000.0,13653000.0,28461000.0,5334900.0,,,373320000.0,99826000.0,21156000.0,,,47404000.0,157850000.0,13899000.0,154460000.0,105000000.0,12441000.0,399290000.0,46780000.0,174840000.0,,190330000.0,5352900000.0,574730000.0,6470300000.0,79135000.0,131240000.0,,106210000.0,266990000.0,66502000.0,243210000.0,2402000000.0,9584400.0,88560000.0,265900000.0,,,1417800000.0,1031300000.0,,40309000.0,48733000.0,164550000.0,2358100000.0,172830000.0,249320000.0,9623600000.0,3209200000.0,310230000.0,97519000.0,1473400000.0,793000000.0,98518000.0,6580400.0,139250000.0,61247000.0,1090200000.0,224200000.0,370100000.0,24372000.0,,50678000.0,560970000.0,1197500000.0,187470000.0,4944200.0,9426900000.0,8965600.0,363310000.0,5034600000.0,,971290000.0,9582700.0,55930000.0,1223800000.0,,40863000.0,524050000.0,90242000.0,72285000.0,,5800600000.0,230900000.0,18645000.0,11669000.0,35760000.0,11818000.0,72690000.0,81305000.0,50292000.0,11072000.0,147700000.0,2811500000.0,222270000.0,152580000.0,1272000000.0,245970000.0,4791700000.0,,121860000.0,15134000.0,72840000.0,9383800.0,39376000.0,8463600.0,,40288000.0,283210000.0,119960000.0,8304700000.0,645750000.0,,8388400.0,922060000.0,13356000000.0,,791000000.0,237480000.0,455240000.0,232710000.0,1051900000.0,159670000.0,116620000.0,894600000.0,1120100000.0,,60514000.0,202180000.0,165880000.0,1442200000.0,,,67163000.0,4336900.0,73977000.0,134310000.0,,1117700000.0,35557000.0,133690000.0,542500000.0,1826100000.0,667200000.0,228900000.0,,330720000.0,207390000.0,54031000.0,42491000.0,208160000.0,,63948000.0,36623000.0,380120000.0,,,171950000.0,90756000.0,,638800000.0,6261100000.0,235130000.0,4082700.0,60462000.0,3581200000.0,,,75122000.0,39182000.0,99790000.0,31427000.0,14407000.0,94047000.0,192800000.0,341750000.0,,165140000.0,134870000.0,390450000.0,611260000.0,65768000.0,23087000.0,994650000.0,62436000.0,39080000.0,86168000.0,107260000.0,6738300.0,5297600000.0,391360000.0,,23989000.0,,,,91925000.0,33312000.0,203830000.0,2615500000.0,,,476780000.0,226930000.0,49096000.0,987100000.0,112750000.0,3751000000.0,56904000.0,5605500000.0,50177000.0,299250000.0,435110000.0,35715000.0,203530000.0,64936000.0,33429000.0,49161000.0,5120800000.0,10111000.0,1421900000.0,263020000.0,66148000.0,7762000.0,116760000.0,,24033000.0,,54915000.0 +2020_05_14_17_28_Q-Exactive-HF-X-Orbitrap_6070,,,18422000000.0,162190000.0,,,,334350000.0,409160000.0,19515000.0,24517000.0,,32519000.0,808230000.0,62685000.0,32973000.0,,282520000.0,10690000.0,76047000.0,900260000.0,6563400.0,,1254600000.0,138890000.0,597030000.0,12535000.0,463050000.0,52321000.0,29243000.0,31863000.0,30233000.0,3319300000.0,,,55084000.0,14553000000.0,19237000.0,2168600000.0,,192810000.0,98892000.0,1618600000.0,582370000.0,215030000.0,658270000.0,42354000.0,93969000.0,,45805000.0,6471400.0,,413750000.0,308980000.0,13570000.0,11625000.0,45213000.0,195540000.0,254130000.0,2153500000.0,,120010000.0,3604400.0,166480000.0,23123000.0,,,2352600000.0,,890710000.0,88572000.0,9910100.0,,96288000.0,195610000.0,4053500.0,554470000.0,78609000.0,64115000.0,1023200000.0,216220000.0,90153000.0,176830000.0,,,36994000.0,28522000.0,77464000.0,306160000.0,33828000.0,8561500.0,,40054000.0,72346000.0,14533000.0,48950000.0,189280000.0,10138000.0,91120000.0,48223000.0,3186300000.0,1026300000.0,453880000.0,,,1061800000.0,,260800000.0,,11076000.0,249760000.0,134890000.0,,,,49770000.0,,193800000.0,771140000.0,73764000.0,104340000.0,291590000.0,55242000.0,1291400000.0,45899000.0,,10919000.0,298900000.0,,360720000.0,96354000.0,29903000.0,61682000.0,72556000.0,19428000.0,,85111000.0,6679200000.0,,4917300.0,15154000.0,,68731000.0,1406800000.0,,7062400.0,157370000.0,11499000.0,77759000.0,5439900.0,259990000.0,,40888000.0,110810000.0,395010000.0,406240000.0,168670000.0,123680000.0,620440000.0,189190000.0,1580900000.0,,285090000.0,75925000.0,27185000.0,126070000.0,152400000.0,121160000.0,102210000.0,327390000.0,138190000.0,39671000.0,59417000.0,,7620400.0,,560370000.0,50074000.0,297920000.0,,36041000.0,108540000.0,57510000.0,377970000.0,,1847700000.0,77745000.0,1976600000.0,935580000.0,71971000.0,162980000.0,147370000.0,55698000.0,618360000.0,21340000.0,,1022200000.0,284890000.0,203440000.0,,199670000.0,210820000.0,452900000.0,15477000.0,8052700000.0,19531000.0,86092000.0,47904000.0,37370000.0,,97230000.0,22462000.0,1079900000.0,,150690000.0,239870000.0,,880610000.0,886510000.0,,81342000.0,1203300000.0,108630000.0,36819000.0,10330000000.0,38175000.0,14294000.0,5289800.0,,,,393680000.0,107910000.0,63427000.0,,,34917000.0,161020000.0,27110000.0,173330000.0,142590000.0,16696000.0,398860000.0,46540000.0,272330000.0,,154830000.0,5735600000.0,774010000.0,7369500000.0,38544000.0,82887000.0,,84053000.0,232810000.0,66522000.0,287400000.0,2647500000.0,24355000.0,94971000.0,338890000.0,,,1770200000.0,654030000.0,,21775000.0,56951000.0,182720000.0,2702700000.0,211490000.0,269610000.0,10830000000.0,3636900000.0,292350000.0,91652000.0,1635100000.0,824840000.0,88687000.0,13490000.0,139540000.0,24847000.0,1059300000.0,249940000.0,260500000.0,27060000.0,,98295000.0,512310000.0,1175300000.0,305320000.0,11761000.0,9215100000.0,10202000.0,313920000.0,4782700000.0,,1073900000.0,22009000.0,152380000.0,1400400000.0,,50025000.0,480000000.0,99948000.0,116750000.0,,5424100000.0,255250000.0,7659400.0,,22254000.0,12642000.0,145260000.0,108310000.0,60706000.0,,122260000.0,3460800000.0,229880000.0,197100000.0,1338000000.0,293820000.0,4179500000.0,761430000.0,140700000.0,23740000.0,93750000.0,,36129000.0,8919600.0,,47414000.0,228060000.0,89455000.0,8256700000.0,455250000.0,,,1269100000.0,5598100000.0,,614920000.0,200560000.0,473870000.0,350570000.0,1168200000.0,166430000.0,119180000.0,966070000.0,1157400000.0,,122960000.0,184490000.0,352290000.0,1781400000.0,,,57768000.0,22595000.0,56340000.0,147980000.0,2896600.0,1265300000.0,23598000.0,127070000.0,636460000.0,1868500000.0,501230000.0,270850000.0,,229530000.0,225840000.0,71193000.0,96763000.0,95561000.0,,50213000.0,,419340000.0,,,274890000.0,155490000.0,,604740000.0,6034400000.0,224810000.0,14227000.0,83604000.0,2954000000.0,,,81317000.0,39980000.0,106100000.0,44610000.0,39572000.0,139690000.0,224540000.0,430470000.0,25806000.0,175060000.0,170730000.0,200150000.0,571970000.0,111650000.0,26383000.0,1149900000.0,90898000.0,28973000.0,31528000.0,244730000.0,,6429900000.0,341550000.0,,21379000.0,,7660700.0,,97827000.0,32322000.0,178400000.0,2542300000.0,,,485660000.0,235800000.0,,1065900000.0,154300000.0,3257300000.0,88934000.0,5799000000.0,224580000.0,360680000.0,361700000.0,35507000.0,185170000.0,18894000.0,16325000.0,,5104200000.0,11427000.0,1547600000.0,132240000.0,50055000.0,7846800.0,,,18788000.0,,51706000.0 +2020_05_14_20_11_Q-Exactive-HF-X-Orbitrap_6070,,,19662000000.0,179880000.0,,,,493790000.0,443280000.0,24200000.0,31478000.0,,39348000.0,922120000.0,48780000.0,,,239070000.0,12874000.0,97628000.0,982190000.0,20551000.0,60452000.0,1334600000.0,188540000.0,697360000.0,39429000.0,414170000.0,63756000.0,34180000.0,56029000.0,59977000.0,3520400000.0,,,99474000.0,15991000000.0,59900000.0,2645400000.0,101940000.0,254850000.0,102580000.0,1680100000.0,541440000.0,220130000.0,789660000.0,78004000.0,98091000.0,,67831000.0,23910000.0,,480510000.0,224320000.0,26617000.0,11431000.0,72154000.0,238460000.0,272290000.0,2578900000.0,120360000.0,154540000.0,24595000.0,222110000.0,72768000.0,,,2742100000.0,,720120000.0,94231000.0,10267000.0,,84720000.0,188170000.0,,408070000.0,115260000.0,53180000.0,1500700000.0,107060000.0,98559000.0,213600000.0,,,524300000.0,10825000.0,26264000.0,382220000.0,21302000.0,35905000.0,11831000.0,49977000.0,105340000.0,24394000.0,47462000.0,223640000.0,11253000.0,112320000.0,43785000.0,3232400000.0,1041300000.0,536290000.0,,,2933000000.0,,313940000.0,,,269480000.0,151640000.0,,,,57837000.0,,238280000.0,734370000.0,104990000.0,146980000.0,294500000.0,31342000.0,1488100000.0,54401000.0,,10271000.0,518240000.0,,442820000.0,79893000.0,31609000.0,19543000.0,94835000.0,,,125190000.0,8390900000.0,,,13958000.0,,66364000.0,1498000000.0,,,104040000.0,31936000.0,57709000.0,5426500.0,273820000.0,,70724000.0,96929000.0,193800000.0,595740000.0,260280000.0,51448000.0,495500000.0,259580000.0,1880800000.0,11499000.0,352950000.0,77015000.0,55321000.0,191750000.0,134530000.0,137090000.0,202910000.0,234120000.0,94627000.0,40425000.0,49808000.0,,17550000.0,14878000.0,764340000.0,65672000.0,375220000.0,,113530000.0,101180000.0,41699000.0,383040000.0,19572000.0,2005800000.0,48671000.0,1970800000.0,973440000.0,72756000.0,162100000.0,151470000.0,65836000.0,736220000.0,,,1323200000.0,562460000.0,169680000.0,,150820000.0,202560000.0,482960000.0,,8050400000.0,12801000.0,124520000.0,69546000.0,18601000.0,,101180000.0,18937000.0,1188600000.0,,193990000.0,329360000.0,,985130000.0,1135600000.0,,102770000.0,1430900000.0,95852000.0,52032000.0,10215000000.0,,20527000.0,27430000.0,,,,348110000.0,136500000.0,39556000.0,,,50682000.0,173790000.0,30248000.0,115660000.0,163620000.0,25174000.0,531850000.0,33816000.0,211340000.0,,95397000.0,6646000000.0,979490000.0,7469200000.0,85582000.0,155890000.0,,61974000.0,355560000.0,85705000.0,313250000.0,2839100000.0,37053000.0,161100000.0,362440000.0,11345000.0,,1795700000.0,1159400000.0,,24488000.0,86058000.0,188360000.0,2746100000.0,243170000.0,295450000.0,13054000000.0,3973600000.0,291530000.0,106430000.0,1988900000.0,1006800000.0,102700000.0,22709000.0,153740000.0,82311000.0,1444200000.0,250480000.0,446210000.0,28279000.0,,103350000.0,497280000.0,1082300000.0,189720000.0,12008000.0,10109000000.0,20026000.0,367020000.0,4531700000.0,,1208100000.0,10900000.0,67877000.0,1473500000.0,,47591000.0,573100000.0,109460000.0,123740000.0,9548000.0,,196130000.0,36291000.0,15580000.0,25690000.0,86731000.0,140340000.0,91693000.0,,11878000.0,129620000.0,3260200000.0,214740000.0,275310000.0,1386700000.0,327270000.0,4269900000.0,780340000.0,155050000.0,71907000.0,143300000.0,,34168000.0,,,49923000.0,185580000.0,70268000.0,9731200000.0,597550000.0,48151000.0,27484000.0,1296700000.0,6014300000.0,,788790000.0,205940000.0,809420000.0,298750000.0,1036700000.0,215480000.0,141480000.0,982990000.0,865750000.0,,145890000.0,191880000.0,347760000.0,1862200000.0,,,87537000.0,24474000.0,61581000.0,185180000.0,,1329000000.0,20000000.0,173190000.0,479940000.0,2098800000.0,904170000.0,264850000.0,,259950000.0,187280000.0,92950000.0,71642000.0,165910000.0,,72571000.0,,503210000.0,,,381350000.0,196090000.0,,560350000.0,7381500000.0,246250000.0,,132870000.0,2925700000.0,,,105510000.0,22790000.0,83407000.0,76361000.0,24715000.0,137090000.0,247060000.0,510610000.0,35430000.0,248610000.0,180780000.0,296300000.0,678250000.0,87031000.0,29252000.0,1349500000.0,97409000.0,46396000.0,,284750000.0,,7275700000.0,462620000.0,,27825000.0,,,11429000.0,24445000.0,30770000.0,207910000.0,3214200000.0,,,534860000.0,246850000.0,,1178200000.0,126430000.0,4316500000.0,74564000.0,6409300000.0,96468000.0,276030000.0,385220000.0,69841000.0,340460000.0,66817000.0,63016000.0,77244000.0,6400400000.0,17700000.0,1590400000.0,164490000.0,93237000.0,11043000.0,,,50093000.0,, +2020_05_15_10_30_Q-Exactive-HF-X-Orbitrap_6070,,,32630000000.0,102070000.0,,,,813920000.0,506240000.0,49695000.0,76356000.0,,44507000.0,1710700000.0,197740000.0,145570000.0,,484430000.0,23450000.0,77386000.0,2938800000.0,15667000.0,494930000.0,1979800000.0,261050000.0,939170000.0,26524000.0,770950000.0,214230000.0,82900000.0,68970000.0,31774000.0,5202100000.0,,32785000.0,147540000.0,22599000000.0,85477000.0,4193300000.0,95499000.0,413160000.0,57182000.0,2599500000.0,1150400000.0,351810000.0,1100900000.0,108890000.0,50295000.0,849630000.0,74231000.0,73403000.0,196790000.0,674340000.0,375440000.0,15188000.0,44747000.0,38281000.0,396860000.0,586030000.0,2717600000.0,120990000.0,223620000.0,,135620000.0,590790000.0,33420000.0,40047000.0,4006100000.0,,1077400000.0,223260000.0,25882000.0,12868000.0,177510000.0,269370000.0,,1088500000.0,355970000.0,123480000.0,2488100000.0,244870000.0,223950000.0,129730000.0,,,121750000.0,111290000.0,133430000.0,103910000.0,79854000.0,,5674300.0,73143000.0,209850000.0,35747000.0,67639000.0,218940000.0,13158000.0,153240000.0,105420000.0,8340400000.0,1356300000.0,954430000.0,,23783000.0,3178900000.0,19376000.0,554620000.0,,15841000.0,447960000.0,185600000.0,,,57172000.0,115750000.0,,409090000.0,995960000.0,363900000.0,522790000.0,317380000.0,61723000.0,2152200000.0,73305000.0,259940000.0,55647000.0,803610000.0,24665000.0,532210000.0,59166000.0,10175000.0,292340000.0,147040000.0,25435000.0,,172830000.0,11993000000.0,58844000.0,55015000.0,57144000.0,196240000.0,83454000.0,2720700000.0,,14808000.0,256500000.0,9070800.0,93495000.0,10119000.0,477410000.0,,222160000.0,189260000.0,472250000.0,1024800000.0,613070000.0,236390000.0,820030000.0,208860000.0,2555800000.0,,595610000.0,107930000.0,42849000.0,186760000.0,381230000.0,152380000.0,237150000.0,741460000.0,181760000.0,41212000.0,124870000.0,6322300.0,41949000.0,79922000.0,866710000.0,399500000.0,445580000.0,,171020000.0,227710000.0,135040000.0,767960000.0,,2136200000.0,164010000.0,3943700000.0,2052300000.0,79864000.0,421310000.0,260350000.0,72502000.0,1056100000.0,77702000.0,42286000.0,1577900000.0,852260000.0,364410000.0,462210000.0,519650000.0,276670000.0,1083400000.0,,14963000000.0,41036000.0,156520000.0,88462000.0,95328000.0,,345330000.0,45778000.0,2414600000.0,,312270000.0,537610000.0,,1063200000.0,1261400000.0,213450000.0,59927000.0,1714500000.0,200610000.0,38643000.0,15842000000.0,70082000.0,34367000.0,20347000.0,,,,602400000.0,170920000.0,93968000.0,295600000.0,,127550000.0,314440000.0,73984000.0,263330000.0,195190000.0,26303000.0,1118000000.0,53909000.0,431420000.0,,676740000.0,9620300000.0,890200000.0,10217000000.0,242730000.0,239340000.0,19423000.0,112160000.0,328130000.0,184870000.0,485260000.0,6685200000.0,30296000.0,189690000.0,440980000.0,6356200.0,,2709800000.0,1507700000.0,38038000.0,36416000.0,83080000.0,201420000.0,4242300000.0,417520000.0,241420000.0,14246000000.0,6918400000.0,466780000.0,165140000.0,2823700000.0,1341100000.0,255910000.0,73149000.0,229620000.0,85829000.0,2748200000.0,415500000.0,463660000.0,40439000.0,35483000.0,86094000.0,698810000.0,1411200000.0,273130000.0,17731000.0,14263000000.0,27034000.0,781650000.0,9910400000.0,,1265500000.0,96980000.0,82954000.0,2238800000.0,,98929000.0,661660000.0,119860000.0,637090000.0,,8546000000.0,207500000.0,22271000.0,41551000.0,29257000.0,123170000.0,273110000.0,121510000.0,24049000.0,101520000.0,298140000.0,6200600000.0,317060000.0,3180000000.0,2380200000.0,352830000.0,6019200000.0,,296370000.0,93770000.0,64474000.0,18145000.0,60029000.0,15889000.0,,74010000.0,318520000.0,30397000.0,13083000000.0,685440000.0,144840000.0,18193000.0,1821500000.0,9909600000.0,,770450000.0,441360000.0,1083100000.0,784980000.0,1499500000.0,279520000.0,246820000.0,1515700000.0,2314600000.0,,263340000.0,541130000.0,723950000.0,3415100000.0,,22095000.0,238150000.0,88479000.0,114090000.0,111400000.0,11209000.0,2116100000.0,59554000.0,256550000.0,1108800000.0,2827800000.0,1047400000.0,412310000.0,,391660000.0,470370000.0,96804000.0,165920000.0,328840000.0,63269000.0,112920000.0,,808920000.0,16872000.0,35098000.0,102460000.0,348960000.0,,1512300000.0,7689200000.0,327550000.0,18134000.0,154600000.0,6197900000.0,,36737000.0,52253000.0,49350000.0,203340000.0,137360000.0,29243000.0,416370000.0,387200000.0,885390000.0,106380000.0,459500000.0,203690000.0,434860000.0,992320000.0,85699000.0,32932000.0,1921100000.0,105440000.0,91334000.0,82288000.0,250230000.0,,8195300000.0,775960000.0,,42291000.0,,,,95209000.0,79755000.0,391710000.0,3629700000.0,11289000.0,,764430000.0,455110000.0,251030000.0,1747300000.0,301590000.0,4250700000.0,88713000.0,9790200000.0,99014000.0,697010000.0,477100000.0,83109000.0,1223800000.0,27852000.0,87279000.0,65113000.0,8402500000.0,12919000.0,2521900000.0,484820000.0,130320000.0,19314000.0,349130000.0,,29580000.0,,107740000.0 +2020_05_20_12_33_Q-Exactive-HF-X-Orbitrap_6070,,,19294000000.0,113070000.0,,8599600.0,,591470000.0,414570000.0,,53064000.0,,,785560000.0,18148000.0,36530000.0,,185880000.0,10854000.0,71336000.0,1573500000.0,,,1523000000.0,143550000.0,770670000.0,37480000.0,441150000.0,86074000.0,30008000.0,28747000.0,33660000.0,3545800000.0,,12586000.0,61056000.0,15826000000.0,86612000.0,3346700000.0,137520000.0,201200000.0,26181000.0,1648900000.0,673930000.0,156810000.0,840030000.0,57051000.0,46801000.0,,26393000.0,,,481000000.0,294410000.0,,10251000.0,25526000.0,232930000.0,316570000.0,2773100000.0,63764000.0,137340000.0,,171120000.0,734940000.0,,4712100.0,2394500000.0,,1176400000.0,99599000.0,,6249400.0,50896000.0,157640000.0,6679200.0,902520000.0,155790000.0,82751000.0,1708500000.0,160190000.0,78203000.0,81709000.0,,,630320000.0,26857000.0,19621000.0,44099000.0,72152000.0,20271000.0,22387000.0,36673000.0,97374000.0,,,366870000.0,8328800.0,118710000.0,37629000.0,4532000000.0,1124300000.0,658980000.0,,12331000.0,1493200000.0,,190910000.0,16687000.0,,303260000.0,111010000.0,,,,55414000.0,,465880000.0,717470000.0,137390000.0,377900000.0,230020000.0,49558000.0,1198200000.0,,35222000.0,352560000.0,502760000.0,44478000.0,339540000.0,,35971000.0,50678000.0,85319000.0,48988000.0,,96544000.0,11236000000.0,8983000.0,,,,44606000.0,1777800000.0,,,260300000.0,5440100.0,38280000.0,5172500.0,492080000.0,25089000.0,55340000.0,91234000.0,570140000.0,847290000.0,222630000.0,100320000.0,662640000.0,238130000.0,1358800000.0,,328740000.0,227540000.0,,220880000.0,94138000.0,122130000.0,125150000.0,282810000.0,133020000.0,69302000.0,34514000.0,11983000.0,10011000.0,,611890000.0,105470000.0,407620000.0,,21633000.0,83087000.0,42802000.0,536410000.0,22580000.0,1619700000.0,42732000.0,3854800000.0,1155300000.0,34022000.0,388620000.0,148820000.0,,601040000.0,34708000.0,,804200000.0,501240000.0,235640000.0,,828390000.0,250180000.0,692950000.0,,1139900000.0,15300000.0,102740000.0,79152000.0,30149000.0,,353660000.0,42428000.0,2092700000.0,,96856000.0,395160000.0,,569980000.0,1131000000.0,,44542000.0,1736200000.0,5512600.0,12584000.0,9456900000.0,45605000.0,,10381000.0,,,,397260000.0,164920000.0,90095000.0,485640000.0,,68383000.0,205070000.0,40754000.0,202960000.0,121920000.0,14498000.0,872520000.0,62559000.0,368540000.0,,86955000.0,7018200000.0,436110000.0,7735400000.0,71171000.0,74393000.0,6315000.0,17714000.0,558850000.0,48363000.0,529260000.0,4503700000.0,59845000.0,110660000.0,321240000.0,24949000.0,,2361400000.0,1033500000.0,,68624000.0,67544000.0,135640000.0,2702300000.0,262190000.0,302860000.0,13109000000.0,3963100000.0,218680000.0,130320000.0,1642700000.0,716520000.0,104370000.0,17403000.0,123200000.0,70861000.0,1874800000.0,222140000.0,435790000.0,,,14969000.0,287220000.0,1515800000.0,306860000.0,,12286000000.0,,481550000.0,5428600000.0,,1242200000.0,,185780000.0,1583600000.0,,36205000.0,493390000.0,69908000.0,330510000.0,,4903100000.0,169800000.0,34007000.0,23774000.0,43910000.0,139510000.0,147330000.0,99482000.0,,26554000.0,205210000.0,5186000000.0,492770000.0,577580000.0,1428400000.0,560740000.0,4599000000.0,,80895000.0,38345000.0,59714000.0,,34377000.0,11925000.0,,44014000.0,187360000.0,62321000.0,9673600000.0,879470000.0,,,1573800000.0,6265700000.0,,326580000.0,385400000.0,688650000.0,,1135800000.0,213960000.0,,1584700000.0,884690000.0,,64939000.0,247820000.0,280920000.0,1421600000.0,,,53342000.0,44846000.0,42516000.0,46700000.0,,992120000.0,119300000.0,149980000.0,752900000.0,1281800000.0,770320000.0,104840000.0,,178130000.0,315820000.0,62564000.0,99251000.0,244680000.0,,110190000.0,,417050000.0,,,63392000.0,30259000.0,,1060200000.0,9343000000.0,226830000.0,,34007000.0,4375800000.0,,,74825000.0,5645800.0,102880000.0,65727000.0,68376000.0,167710000.0,305910000.0,813790000.0,,236680000.0,183250000.0,371010000.0,1010800000.0,118960000.0,36666000.0,1369400000.0,41539000.0,45084000.0,62173000.0,198950000.0,,5559600000.0,396230000.0,,,,21250000.0,,71218000.0,21912000.0,180320000.0,2169700000.0,,,431020000.0,152330000.0,20820000.0,1237800000.0,124360000.0,4067100000.0,58240000.0,6963000000.0,36315000.0,527920000.0,320670000.0,17924000.0,1090100000.0,101860000.0,128070000.0,,6024400000.0,10908000.0,1920000000.0,168490000.0,51931000.0,10048000.0,,,9842300.0,,47400000.0 +2020_05_20_15_35_Q-Exactive-HF-X-Orbitrap_6070,,,28727000000.0,284320000.0,,,17752000.0,941560000.0,450840000.0,21865000.0,78271000.0,,12277000.0,938740000.0,9626200.0,44294000.0,,342410000.0,24786000.0,87073000.0,1804700000.0,17789000.0,413610000.0,1971400000.0,255590000.0,790520000.0,38563000.0,711510000.0,181640000.0,42717000.0,27424000.0,37150000.0,4438700000.0,,,140220000.0,20481000000.0,115360000.0,3517000000.0,120910000.0,324450000.0,76184000.0,2214200000.0,698260000.0,373630000.0,1379900000.0,75776000.0,118150000.0,,58141000.0,65710000.0,112290000.0,735990000.0,396660000.0,8374400.0,50707000.0,89185000.0,306350000.0,487700000.0,2610600000.0,98509000.0,220550000.0,,202930000.0,202520000.0,,12350000.0,3159500000.0,,892650000.0,152390000.0,33904000.0,37523000.0,103370000.0,237060000.0,,1067800000.0,183310000.0,39277000.0,2574200000.0,369650000.0,96696000.0,192700000.0,,,69505000.0,124600000.0,141360000.0,44475000.0,,13660000.0,5439100.0,54909000.0,88475000.0,15733000.0,26810000.0,339250000.0,17233000.0,141020000.0,52600000.0,4267300000.0,1211800000.0,718960000.0,,25451000.0,2356600000.0,,269460000.0,24279000.0,34879000.0,413420000.0,152660000.0,,,,89243000.0,15074000.0,384670000.0,924910000.0,224280000.0,245360000.0,596120000.0,44273000.0,1698300000.0,123380000.0,,40231000.0,728120000.0,40778000.0,373860000.0,,49000000.0,71600000.0,160680000.0,32057000.0,,183970000.0,13438000000.0,29944000.0,26485000.0,31607000.0,90522000.0,66924000.0,3428500000.0,63369000.0,5853400.0,90683000.0,23714000.0,36119000.0,13459000.0,410300000.0,,51144000.0,133280000.0,424140000.0,892940000.0,403380000.0,188500000.0,554110000.0,282580000.0,1978600000.0,,399960000.0,62374000.0,80157000.0,577640000.0,123170000.0,114170000.0,302220000.0,917040000.0,151150000.0,,51498000.0,,43898000.0,131920000.0,849220000.0,117860000.0,526980000.0,,147300000.0,146110000.0,116740000.0,622680000.0,15367000.0,2732200000.0,75391000.0,4430000000.0,1741500000.0,94869000.0,307510000.0,180730000.0,,633890000.0,36088000.0,23680000.0,1181200000.0,694840000.0,268740000.0,,338520000.0,301320000.0,1042700000.0,,11747000000.0,50485000.0,15193000.0,90268000.0,51445000.0,,254810000.0,66735000.0,1815700000.0,,234850000.0,598870000.0,,653250000.0,1428900000.0,78910000.0,86222000.0,1290900000.0,63628000.0,51570000.0,8327400000.0,49639000.0,21141000.0,47701000.0,,,,586480000.0,160710000.0,53824000.0,,,53462000.0,179360000.0,69146000.0,206720000.0,175760000.0,,886820000.0,62691000.0,445730000.0,,138980000.0,7525400000.0,846110000.0,9269600000.0,50062000.0,247540000.0,,58950000.0,296870000.0,41827000.0,521290000.0,5746700000.0,74835000.0,124340000.0,426060000.0,15797000.0,,2886000000.0,1769500000.0,,66696000.0,69277000.0,244270000.0,3495800000.0,325810000.0,422100000.0,12650000000.0,4593500000.0,290230000.0,149940000.0,2454600000.0,936140000.0,224040000.0,33281000.0,184600000.0,121240000.0,2416400000.0,309670000.0,520090000.0,31692000.0,,61958000.0,548080000.0,924910000.0,531590000.0,,13007000000.0,11955000.0,526480000.0,7080500000.0,,2651400000.0,52315000.0,94839000.0,1796400000.0,,14137000.0,792800000.0,109010000.0,274600000.0,,,310500000.0,71021000.0,23610000.0,81164000.0,144780000.0,112130000.0,116630000.0,44157000.0,57957000.0,342110000.0,6645700000.0,372400000.0,1920700000.0,1735800000.0,449770000.0,4390900000.0,,164050000.0,62925000.0,71143000.0,24835000.0,109650000.0,18266000.0,,116280000.0,227350000.0,111030000.0,10936000000.0,1045600000.0,41555000.0,21413000.0,1422300000.0,7209400000.0,,1070100000.0,293620000.0,725870000.0,461940000.0,1377200000.0,240090000.0,88412000.0,1298500000.0,850270000.0,,173040000.0,746910000.0,463090000.0,2547700000.0,,416090000.0,124030000.0,110990000.0,41588000.0,159020000.0,,1204600000.0,8261900.0,252260000.0,890050000.0,1812400000.0,1167600000.0,384670000.0,,277190000.0,252870000.0,69942000.0,93585000.0,140300000.0,43984000.0,29637000.0,153020000.0,522820000.0,,,129160000.0,17471000.0,,1204100000.0,7485200000.0,250430000.0,,74852000.0,3713400000.0,,26345000.0,104340000.0,107920000.0,147720000.0,88908000.0,58654000.0,232820000.0,366940000.0,906890000.0,36259000.0,329180000.0,409700000.0,429940000.0,1186800000.0,65844000.0,35192000.0,1984900000.0,86274000.0,98984000.0,105440000.0,288890000.0,,8374600000.0,526570000.0,,16497000.0,,15503000.0,,44704000.0,31787000.0,206790000.0,3487900000.0,,,318310000.0,355050000.0,156770000.0,1575400000.0,291440000.0,4147700000.0,150560000.0,7924200000.0,70416000.0,466000000.0,509940000.0,55221000.0,867120000.0,75206000.0,74947000.0,63644000.0,7360200000.0,54522000.0,2800500000.0,253390000.0,93828000.0,14196000.0,,,25599000.0,,101980000.0 +2020_05_22_14_57_Q-Exactive-HF-X-Orbitrap_6070,,,32944000000.0,296440000.0,,22298000.0,9004300.0,824760000.0,401240000.0,17158000.0,49187000.0,,22071000.0,1141100000.0,88049000.0,94839000.0,,329810000.0,6377400.0,45172000.0,1226400000.0,25109000.0,,1727700000.0,265380000.0,762340000.0,20567000.0,760820000.0,120330000.0,17169000.0,25780000.0,74133000.0,4324400000.0,,9961000.0,119680000.0,22701000000.0,7664900.0,2811400000.0,,446140000.0,99606000.0,2792000000.0,801290000.0,265630000.0,1120600000.0,66863000.0,103120000.0,,443190000.0,94955000.0,17645000.0,737970000.0,460920000.0,,28331000.0,38988000.0,376880000.0,314910000.0,3922800000.0,145000000.0,130990000.0,,146510000.0,45706000.0,56087000.0,8290300.0,3145900000.0,,348370000.0,91735000.0,19583000.0,106570000.0,56908000.0,128630000.0,,675480000.0,163710000.0,80980000.0,2088400000.0,252730000.0,94310000.0,392860000.0,,,482440000.0,65256000.0,84504000.0,50411000.0,69659000.0,63449000.0,10096000.0,149940000.0,164890000.0,43997000.0,34186000.0,294700000.0,15235000.0,83878000.0,66627000.0,3493400000.0,992340000.0,632650000.0,,29975000.0,3055300000.0,,119650000.0,,,284960000.0,120760000.0,,,30109000.0,110750000.0,,280800000.0,1229000000.0,150740000.0,336180000.0,584770000.0,396580000.0,1979600000.0,83827000.0,,35466000.0,730810000.0,,648890000.0,41985000.0,20491000.0,106960000.0,76905000.0,33183000.0,,158670000.0,9547000000.0,81262000.0,32496000.0,27808000.0,234990000.0,65048000.0,2126300000.0,,9922500.0,105650000.0,26140000.0,140020000.0,9300200.0,325660000.0,,24611000.0,129190000.0,440430000.0,898930000.0,195090000.0,127710000.0,624970000.0,225240000.0,2477700000.0,,244650000.0,100930000.0,32040000.0,,261630000.0,101580000.0,128320000.0,374310000.0,91136000.0,,59838000.0,7200300.0,28473000.0,,995560000.0,94790000.0,331300000.0,,106550000.0,103250000.0,73314000.0,712410000.0,27697000.0,3218800000.0,88609000.0,2692500000.0,2292600000.0,68718000.0,205960000.0,214780000.0,,1033400000.0,27454000.0,,1388100000.0,613100000.0,208190000.0,,479570000.0,129290000.0,555540000.0,45458000.0,15003000000.0,,186960000.0,12808000.0,87328000.0,,48447000.0,22623000.0,1496700000.0,,273830000.0,383710000.0,,895890000.0,952920000.0,21184000.0,108780000.0,1332900000.0,88688000.0,54519000.0,11016000000.0,100030000.0,36625000.0,45037000.0,,,,508400000.0,97018000.0,50759000.0,,,81567000.0,206300000.0,85764000.0,161150000.0,144890000.0,,851390000.0,62156000.0,270090000.0,,140150000.0,8763300000.0,808740000.0,9049000000.0,146510000.0,120390000.0,,87742000.0,140120000.0,54728000.0,759610000.0,3084400000.0,35014000.0,137830000.0,328280000.0,14469000.0,5304300.0,3686800000.0,1146900000.0,,32081000.0,126810000.0,171250000.0,3693700000.0,425910000.0,347520000.0,15664000000.0,4924100000.0,368190000.0,137920000.0,2357400000.0,1087500000.0,189460000.0,24266000.0,196640000.0,125200000.0,2278800000.0,414030000.0,449050000.0,58803000.0,6925000.0,87681000.0,302220000.0,235280000.0,276360000.0,34634000.0,13888000000.0,15126000.0,429550000.0,6385900000.0,,1655500000.0,18412000.0,,1292600000.0,,58717000.0,372220000.0,132900000.0,91726000.0,,7179700000.0,292660000.0,35630000.0,27768000.0,26894000.0,163630000.0,57489000.0,172450000.0,29952000.0,,209310000.0,4007400000.0,370960000.0,2036800000.0,1945100000.0,400430000.0,3230000000.0,,178770000.0,35541000.0,75622000.0,,53681000.0,20982000.0,,62147000.0,215040000.0,54237000.0,10133000000.0,820490000.0,,35046000.0,1725000000.0,20494000000.0,465710000.0,2290000000.0,316530000.0,1278300000.0,498540000.0,1104600000.0,231450000.0,73969000.0,1381500000.0,1445800000.0,,166740000.0,262970000.0,,3380300000.0,,,135180000.0,68211000.0,63551000.0,274920000.0,,1681300000.0,,353180000.0,557790000.0,1468600000.0,1611000000.0,190290000.0,,333730000.0,208060000.0,77274000.0,47131000.0,136520000.0,9866300.0,113270000.0,,662360000.0,,27812000.0,192440000.0,25654000.0,,1549200000.0,5776900000.0,279810000.0,9069500.0,155100000.0,4241900000.0,,,65227000.0,35302000.0,168630000.0,46861000.0,,144360000.0,412200000.0,747840000.0,24988000.0,469000000.0,209840000.0,472910000.0,970070000.0,159770000.0,42981000.0,1187800000.0,137680000.0,61678000.0,,395820000.0,,5660700000.0,515880000.0,,,4642500.0,,,93089000.0,58520000.0,336680000.0,4482000000.0,,,672940000.0,377080000.0,244870000.0,1591600000.0,115280000.0,4231900000.0,106540000.0,6859100000.0,28673000.0,337210000.0,474750000.0,59681000.0,22597000.0,29131000.0,13911000.0,72421000.0,6142600000.0,50337000.0,3247700000.0,54275000.0,89485000.0,13327000.0,,100460000.0,125180000.0,,73071000.0 +2020_05_22_17_43_Q-Exactive-HF-X-Orbitrap_6070,,,30697000000.0,172150000.0,,17624000.0,3268700.0,788540000.0,444560000.0,34973000.0,29019000.0,,14543000.0,1689700000.0,104560000.0,77878000.0,,351050000.0,,120750000.0,1878700000.0,21160000.0,311590000.0,1609900000.0,262580000.0,959760000.0,39228000.0,338500000.0,134960000.0,70728000.0,58770000.0,56219000.0,5607500000.0,,,144430000.0,24279000000.0,54682000.0,4097500000.0,,441740000.0,110230000.0,2737600000.0,1143100000.0,269700000.0,1481900000.0,154470000.0,98278000.0,700000000.0,62725000.0,36279000.0,63351000.0,942180000.0,490260000.0,,52224000.0,29711000.0,405550000.0,583660000.0,3224600000.0,161990000.0,179340000.0,,176140000.0,211640000.0,61468000.0,8523400.0,4841100000.0,,707150000.0,,65003000.0,18784000.0,168140000.0,253750000.0,,923570000.0,164220000.0,46766000.0,2685100000.0,439850000.0,143300000.0,164740000.0,,,295980000.0,12864000.0,135290000.0,102560000.0,22584000.0,33136000.0,,95590000.0,255880000.0,25013000.0,44238000.0,520000000.0,20114000.0,205850000.0,96722000.0,4784100000.0,1063800000.0,919960000.0,,22336000.0,3507600000.0,4890500.0,459420000.0,,14051000.0,395960000.0,279220000.0,,,20437000.0,98163000.0,,352420000.0,1103600000.0,222830000.0,454340000.0,485450000.0,107750000.0,7107800000.0,59763000.0,,25270000.0,848780000.0,18929000.0,566150000.0,,27816000.0,149310000.0,105240000.0,34343000.0,,175250000.0,,71783000.0,24059000.0,56909000.0,243520000.0,62399000.0,2568100000.0,12521000.0,8885500.0,178210000.0,8941600.0,82391000.0,19157000.0,412130000.0,,129760000.0,138050000.0,190320000.0,975470000.0,312960000.0,181300000.0,752220000.0,305050000.0,2421000000.0,,562790000.0,88359000.0,45859000.0,568320000.0,292490000.0,174910000.0,142540000.0,898370000.0,215930000.0,39065000.0,,,26825000.0,55774000.0,1085300000.0,139490000.0,622530000.0,,168380000.0,121260000.0,111970000.0,895630000.0,29967000.0,1974200000.0,123760000.0,3133400000.0,2005500000.0,34598000.0,267550000.0,314190000.0,,1121200000.0,27142000.0,50365000.0,1382300000.0,554460000.0,211500000.0,142540000.0,435510000.0,221110000.0,674940000.0,,1482800000.0,73424000.0,220150000.0,79512000.0,90904000.0,,235340000.0,62270000.0,2146200000.0,,246740000.0,516580000.0,,985930000.0,1495600000.0,51624000.0,102010000.0,1274200000.0,191230000.0,59724000.0,15306000000.0,99312000.0,14060000.0,16596000.0,10459000.0,,,692680000.0,153980000.0,73776000.0,321120000.0,,60421000.0,230850000.0,48318000.0,192790000.0,231320000.0,,735040000.0,72856000.0,516130000.0,,152050000.0,8616700000.0,1082300000.0,11141000000.0,142270000.0,163990000.0,,110120000.0,340220000.0,133060000.0,475870000.0,4740900000.0,42557000.0,189910000.0,500840000.0,19640000.0,,3279900000.0,1556100000.0,,73005000.0,137860000.0,430610000.0,3455100000.0,440340000.0,445800000.0,12742000000.0,5488000000.0,530250000.0,218860000.0,2816900000.0,1180400000.0,172970000.0,71227000.0,264730000.0,188380000.0,1944600000.0,707730000.0,629280000.0,44382000.0,31991000.0,56030000.0,422050000.0,1451800000.0,366180000.0,26776000.0,14127000000.0,17096000.0,611420000.0,8998200000.0,,1758400000.0,27021000.0,1526100000.0,1913600000.0,,35614000.0,783870000.0,85018000.0,216860000.0,,8588400000.0,289130000.0,43220000.0,51872000.0,17800000.0,250700000.0,224640000.0,201090000.0,20964000.0,33675000.0,200180000.0,8410000000.0,348080000.0,2206200000.0,2497400000.0,636980000.0,5884300000.0,,207290000.0,90578000.0,77694000.0,22586000.0,89776000.0,18720000.0,,75778000.0,372360000.0,48666000.0,12345000000.0,983460000.0,18116000.0,,1999400000.0,9247800000.0,,1140300000.0,363920000.0,803510000.0,,1376900000.0,288900000.0,369070000.0,1636000000.0,1935900000.0,,199840000.0,338360000.0,312800000.0,3730000000.0,,22254000.0,192380000.0,60718000.0,125600000.0,166430000.0,,2348200000.0,47752000.0,307630000.0,1040300000.0,2503900000.0,1121400000.0,355000000.0,,429310000.0,244900000.0,45610000.0,150480000.0,314310000.0,58943000.0,44740000.0,,974800000.0,43172000.0,,121780000.0,294410000.0,,1419200000.0,8738800000.0,249430000.0,11704000.0,135410000.0,5351300000.0,,17537000.0,160700000.0,55454000.0,135290000.0,86376000.0,,220830000.0,395470000.0,741290000.0,36477000.0,526500000.0,262310000.0,560030000.0,1168500000.0,232590000.0,31467000.0,1983300000.0,108270000.0,77504000.0,93190000.0,382350000.0,,7876300000.0,402190000.0,,28242000.0,13392000.0,,,416840000.0,16702000.0,420190000.0,3649400000.0,26221000.0,,556040000.0,449000000.0,,1735400000.0,218490000.0,4792400000.0,155570000.0,9214300000.0,117120000.0,351550000.0,504090000.0,116300000.0,1030600000.0,142770000.0,44507000.0,87016000.0,8609700000.0,21521000.0,2531800000.0,168320000.0,56058000.0,22182000.0,,,45924000.0,,203710000.0 +2020_05_26_14_20_Q-Exactive-HF-X-Orbitrap_6070,,,45390000000.0,313940000.0,,,,1487500000.0,935980000.0,100130000.0,45306000.0,,106170000.0,1481300000.0,163790000.0,,,482710000.0,,169770000.0,2572500000.0,,158630000.0,3138700000.0,394760000.0,1393500000.0,88939000.0,1100900000.0,139840000.0,89269000.0,101400000.0,,7143800000.0,,,171730000.0,36880000000.0,116390000.0,6990300000.0,199960000.0,671970000.0,188930000.0,3075200000.0,1221500000.0,601130000.0,1421600000.0,247840000.0,193990000.0,,569630000.0,,,1370500000.0,739470000.0,39236000.0,74763000.0,167820000.0,333500000.0,682030000.0,6859700000.0,215980000.0,216610000.0,47304000.0,301640000.0,,,33821000.0,7407700000.0,,1297900000.0,113800000.0,,20236000.0,186220000.0,445820000.0,17951000.0,2236400000.0,312590000.0,151620000.0,4313800000.0,344480000.0,193350000.0,420510000.0,,,136690000.0,160820000.0,156850000.0,29748000.0,,65396000.0,19124000.0,217560000.0,187020000.0,,,369480000.0,20723000.0,177170000.0,126580000.0,8153400000.0,2134200000.0,1671600000.0,,69907000.0,11088000000.0,18794000.0,316320000.0,10189000.0,,608440000.0,563320000.0,,,,59208000.0,,522020000.0,2488000000.0,403360000.0,549680000.0,866570000.0,149180000.0,3973200000.0,198130000.0,47921000.0,21773000.0,1223000000.0,,517530000.0,113960000.0,106900000.0,364970000.0,200870000.0,96698000.0,,311400000.0,19413000000.0,,71333000.0,108850000.0,148900000.0,67513000.0,3035100000.0,62570000.0,,380190000.0,34798000.0,1316600000.0,,527840000.0,88060000.0,134860000.0,155820000.0,905150000.0,964420000.0,708450000.0,87981000.0,1499800000.0,430630000.0,3602300000.0,,768550000.0,178180000.0,17845000.0,384870000.0,384720000.0,278770000.0,225000000.0,1383000000.0,377110000.0,76359000.0,160320000.0,13126000.0,57343000.0,57035000.0,1772300000.0,380970000.0,965410000.0,,128540000.0,104110000.0,174340000.0,1114200000.0,55940000.0,4428900000.0,74866000.0,5248000000.0,3604300000.0,172980000.0,416610000.0,472020000.0,27974000.0,2058200000.0,19044000.0,70397000.0,3158400000.0,1034900000.0,464990000.0,,916740000.0,,1391700000.0,,26340000000.0,190160000.0,240530000.0,96300000.0,125170000.0,,550520000.0,54379000.0,3623400000.0,,469050000.0,561170000.0,,1289800000.0,2088600000.0,50799000.0,85459000.0,1851400000.0,302540000.0,107900000.0,20506000000.0,255550000.0,34402000.0,18972000.0,20735000.0,,,1370000000.0,186240000.0,45130000.0,,,64631000.0,553680000.0,113230000.0,432480000.0,356170000.0,,1840700000.0,103180000.0,344580000.0,,361190000.0,13421000000.0,2002300000.0,18133000000.0,291180000.0,323710000.0,,227170000.0,691130000.0,154080000.0,736460000.0,7798300000.0,66540000.0,386430000.0,283940000.0,40959000.0,,4407900000.0,2481400000.0,31316000.0,63446000.0,239390000.0,610440000.0,9167900000.0,687730000.0,512320000.0,32607000000.0,8413300000.0,645030000.0,162770000.0,4924400000.0,2367100000.0,225040000.0,98413000.0,340930000.0,189920000.0,2817100000.0,668680000.0,1064500000.0,69205000.0,16714000.0,292580000.0,639950000.0,1844800000.0,655260000.0,36312000.0,22273000000.0,,839820000.0,15134000000.0,,2586900000.0,103920000.0,2948700000.0,3537500000.0,,104920000.0,654050000.0,144290000.0,278590000.0,,14574000000.0,231860000.0,77923000.0,33236000.0,76271000.0,231610000.0,393560000.0,238600000.0,62186000.0,47176000.0,592870000.0,13192000000.0,483460000.0,2988700000.0,3448200000.0,871590000.0,8960000000.0,2463200000.0,481200000.0,111690000.0,49833000.0,66785000.0,98779000.0,44703000.0,,140070000.0,522950000.0,161040000.0,21698000000.0,1397200000.0,39558000.0,47173000.0,4175200000.0,17873000000.0,,2079900000.0,554900000.0,1508800000.0,918340000.0,2773500000.0,492720000.0,730830000.0,1833600000.0,3755900000.0,,367560000.0,188970000.0,530680000.0,5174400000.0,,,372520000.0,75962000.0,171460000.0,530690000.0,,4354800000.0,194890000.0,424220000.0,1750600000.0,4173300000.0,2044900000.0,399680000.0,,903160000.0,669390000.0,194870000.0,145150000.0,384220000.0,,292380000.0,,942900000.0,28752000.0,46033000.0,373100000.0,218870000.0,,1930000000.0,19372000000.0,679430000.0,,194610000.0,6624300000.0,,72904000.0,213550000.0,66927000.0,255900000.0,149750000.0,,206800000.0,648120000.0,1557100000.0,96728000.0,781440000.0,456910000.0,662360000.0,1746700000.0,104600000.0,115940000.0,3739000000.0,,240370000.0,171710000.0,321350000.0,,14519000000.0,645240000.0,,,,,19105000.0,138020000.0,25102000.0,575050000.0,5921600000.0,55698000.0,,1098300000.0,636430000.0,,2322900000.0,302160000.0,7803100000.0,175670000.0,15857000000.0,109580000.0,827970000.0,1160800000.0,140940000.0,83079000.0,90975000.0,46037000.0,108180000.0,14982000000.0,,5382000000.0,405480000.0,113690000.0,57102000.0,,,29029000.0,,196310000.0 +2020_05_27_13_57_Q-Exactive-HF-X-Orbitrap_6070,,,83324000000.0,241760000.0,,,,3149700000.0,1572500000.0,219930000.0,197580000.0,,137790000.0,4550500000.0,209140000.0,168530000.0,,554690000.0,19899000.0,149710000.0,6816700000.0,38311000.0,567780000.0,6635100000.0,1192900000.0,3380000000.0,228680000.0,2007500000.0,868290000.0,138060000.0,181790000.0,79142000.0,18072000000.0,,28674000.0,674590000.0,80447000000.0,308080000.0,12632000000.0,471250000.0,2018100000.0,508370000.0,10382000000.0,2987900000.0,1317200000.0,4565500000.0,392640000.0,138770000.0,2452800000.0,259220000.0,149840000.0,174080000.0,3190100000.0,1583500000.0,,171220000.0,323380000.0,1508300000.0,2154400000.0,7809500000.0,373860000.0,575040000.0,120710000.0,831210000.0,615800000.0,128180000.0,137010000.0,10449000000.0,,3419800000.0,680730000.0,,130170000.0,796820000.0,894810000.0,,3617600000.0,757290000.0,252720000.0,8751500000.0,864300000.0,766630000.0,483940000.0,,15742000.0,479430000.0,152740000.0,455480000.0,459630000.0,152690000.0,172980000.0,64284000.0,324450000.0,598980000.0,110930000.0,,1021700000.0,1281800000.0,635630000.0,265490000.0,14746000000.0,4722200000.0,3420100000.0,,88564000.0,16500000000.0,,1176700000.0,,150190000.0,1471900000.0,944500000.0,,,133330000.0,445910000.0,,1281500000.0,3812000000.0,766360000.0,1187100000.0,2032300000.0,198880000.0,5393000000.0,507690000.0,73303000.0,69469000.0,2977900000.0,125780000.0,1911400000.0,,189210000.0,789290000.0,418500000.0,132860000.0,34579000.0,854770000.0,28844000000.0,,265700000.0,357410000.0,1119700000.0,236320000.0,7752900000.0,105190000.0,,731460000.0,160930000.0,312390000.0,45537000.0,1345900000.0,,468430000.0,695450000.0,1100000000.0,3322400000.0,1572400000.0,653150000.0,3369500000.0,1453000000.0,7173000000.0,,1421300000.0,446570000.0,387080000.0,802840000.0,960260000.0,570900000.0,928360000.0,1574300000.0,628420000.0,51250000.0,134750000.0,26104000.0,199530000.0,146740000.0,2497200000.0,762390000.0,2739200000.0,,286430000.0,652560000.0,646210000.0,2751300000.0,171900000.0,6856700000.0,433890000.0,13541000000.0,4719200000.0,626200000.0,1405200000.0,395030000.0,202170000.0,4476000000.0,126620000.0,,6610000000.0,3124200000.0,577680000.0,376840000.0,1237400000.0,790190000.0,3685400000.0,104880000.0,3689000000.0,101710000.0,135470000.0,534030000.0,396060000.0,,816540000.0,271740000.0,7735800000.0,,1327400000.0,2180900000.0,,2380300000.0,5706500000.0,209820000.0,452040000.0,5457900000.0,547530000.0,200760000.0,38519000000.0,361380000.0,69582000.0,196360000.0,18208000.0,,,1444800000.0,618340000.0,333890000.0,,,271190000.0,1094700000.0,249820000.0,701690000.0,518110000.0,57276000.0,3654800000.0,473440000.0,1669000000.0,,640790000.0,34257000000.0,3309000000.0,36121000000.0,175690000.0,651970000.0,39804000.0,365230000.0,823840000.0,385170000.0,2361800000.0,14195000000.0,372330000.0,1192900000.0,1077600000.0,152200000.0,,13547000000.0,5137100000.0,44187000.0,148070000.0,360830000.0,1462200000.0,16394000000.0,1364000000.0,1834600000.0,53913000000.0,16521000000.0,1507700000.0,477360000.0,11646000000.0,5014100000.0,897950000.0,197210000.0,1069500000.0,801920000.0,8450100000.0,1627500000.0,2452300000.0,119960000.0,28106000.0,638640000.0,1732800000.0,3921800000.0,1970600000.0,167550000.0,33074000000.0,146160000.0,1735500000.0,27131000000.0,85154000.0,4452300000.0,160550000.0,153000000.0,6117800000.0,,353040000.0,2115400000.0,305920000.0,612760000.0,,25198000000.0,1005900000.0,235640000.0,153910000.0,127200000.0,666630000.0,393180000.0,964400000.0,165790000.0,219750000.0,311400000.0,25687000000.0,1710100000.0,,6919500000.0,1999300000.0,21099000000.0,,716820000.0,184260000.0,499330000.0,123200000.0,218720000.0,119780000.0,27620000.0,359380000.0,1936000000.0,329210000.0,37683000000.0,2953200000.0,81533000.0,175360000.0,8163700000.0,25852000000.0,,3513500000.0,1101200000.0,2371200000.0,1414900000.0,4809400000.0,855500000.0,717550000.0,6514300000.0,6331200000.0,,844020000.0,913790000.0,1554900000.0,10932000000.0,,,641400000.0,389640000.0,757020000.0,381070000.0,,5926800000.0,229370000.0,647420000.0,3413300000.0,7242200000.0,6437800000.0,1279300000.0,,1347600000.0,825080000.0,390890000.0,550460000.0,882850000.0,164190000.0,364320000.0,,2270500000.0,32725000.0,76118000.0,549610000.0,293810000.0,,4953700000.0,27997000000.0,1337000000.0,23256000.0,590090000.0,10686000000.0,,138660000.0,531860000.0,258780000.0,433270000.0,431230000.0,181470000.0,961690000.0,1383700000.0,3469700000.0,276390000.0,1920200000.0,1317200000.0,1476200000.0,4421100000.0,902920000.0,185230000.0,7142600000.0,333750000.0,588820000.0,511240000.0,727730000.0,,22000000000.0,1898200000.0,,44575000.0,51738000.0,,26380000.0,405360000.0,170220000.0,973120000.0,13984000000.0,99042000.0,378100000.0,1067100000.0,1638100000.0,733150000.0,5237800000.0,692430000.0,21468000000.0,432500000.0,30568000000.0,346090000.0,1896000000.0,1784700000.0,409680000.0,2647400000.0,388520000.0,178930000.0,395760000.0,27648000000.0,194340000.0,8300200000.0,762720000.0,746600000.0,32824000.0,,638360000.0,263670000.0,27060000.0,507590000.0 +2020_05_28_04_06_Q-Exactive-HF-X-Orbitrap_6070,,,97880000000.0,95044000.0,,,9774300.0,3554900000.0,1586400000.0,253890000.0,233510000.0,,170990000.0,4999600000.0,537550000.0,399670000.0,,1271500000.0,116580000.0,289310000.0,7881800000.0,90765000.0,1203000000.0,6504800000.0,1475500000.0,3983600000.0,195300000.0,2472400000.0,782280000.0,284330000.0,236290000.0,,23599000000.0,,70305000.0,784200000.0,99267000000.0,225750000.0,16965000000.0,349480000.0,2425400000.0,1120800000.0,12827000000.0,4144300000.0,1595100000.0,4815000000.0,295690000.0,171030000.0,3002400000.0,379640000.0,398300000.0,198880000.0,3983200000.0,1706700000.0,49442000.0,168570000.0,366750000.0,1768700000.0,2062400000.0,10556000000.0,671720000.0,1008900000.0,116350000.0,862970000.0,1024100000.0,107750000.0,,14704000000.0,,4172500000.0,,242520000.0,193880000.0,760050000.0,1740700000.0,36976000.0,4833900000.0,1238400000.0,233960000.0,9327300000.0,1131000000.0,607470000.0,664580000.0,,56546000.0,581670000.0,355810000.0,627430000.0,824300000.0,172750000.0,199610000.0,53767000.0,563760000.0,536750000.0,107870000.0,252790000.0,1270200000.0,,980150000.0,358070000.0,17186000000.0,4341100000.0,4431200000.0,,99839000.0,18230000000.0,,1077100000.0,19933000.0,74352000.0,1996800000.0,1124100000.0,,,128360000.0,543910000.0,68535000.0,1804500000.0,5278900000.0,1415600000.0,1418200000.0,2259900000.0,271170000.0,21083000000.0,596860000.0,72058000.0,342940000.0,3381800000.0,92104000.0,2404300000.0,82828000.0,206380000.0,1022900000.0,333790000.0,283760000.0,73763000.0,1011800000.0,43369000000.0,,330550000.0,411540000.0,464860000.0,474950000.0,10440000000.0,232720000.0,26957000.0,808810000.0,146200000.0,538630000.0,33314000.0,1815000000.0,365150000.0,460010000.0,312550000.0,1362000000.0,3893900000.0,1475000000.0,831160000.0,2991200000.0,1013100000.0,8702000000.0,,2295700000.0,497040000.0,477110000.0,1082800000.0,773430000.0,750920000.0,1008600000.0,1667500000.0,833620000.0,74973000.0,181150000.0,77421000.0,232440000.0,96012000.0,3326600000.0,1166500000.0,2215300000.0,,371260000.0,951870000.0,399330000.0,2235800000.0,324890000.0,8769600000.0,387560000.0,16574000000.0,6444200000.0,731330000.0,1670000000.0,442820000.0,30396000.0,5010800000.0,273750000.0,56080000.0,7925900000.0,3288300000.0,1325200000.0,,1948800000.0,927020000.0,2992300000.0,32015000.0,43765000000.0,217450000.0,168490000.0,542760000.0,583040000.0,,1223000000.0,416410000.0,8123600000.0,,1638700000.0,2642800000.0,,2956900000.0,6131700000.0,96807000.0,383590000.0,6871800000.0,660960000.0,465640000.0,53132000000.0,418310000.0,185440000.0,112840000.0,200330000.0,,,3137700000.0,621540000.0,579380000.0,3174000000.0,,312390000.0,1304700000.0,353530000.0,997680000.0,927200000.0,,3294500000.0,594940000.0,4072800000.0,,1232400000.0,47141000000.0,4702200000.0,42909000000.0,771850000.0,925010000.0,50306000.0,431930000.0,761780000.0,573080000.0,2228700000.0,17376000000.0,303890000.0,1537800000.0,1160100000.0,145620000.0,,15798000000.0,7772200000.0,47599000.0,300460000.0,638710000.0,1550700000.0,14722000000.0,2162100000.0,1650200000.0,54364000000.0,21212000000.0,2389300000.0,756540000.0,12306000000.0,5501300000.0,1727400000.0,287230000.0,1297200000.0,554110000.0,8110700000.0,2517600000.0,2210700000.0,176210000.0,99650000.0,675270000.0,2384600000.0,3968200000.0,2214100000.0,107490000.0,46260000000.0,159280000.0,2326100000.0,35157000000.0,,7427400000.0,213460000.0,592280000.0,7942800000.0,,504400000.0,2981800000.0,424740000.0,1116100000.0,,30710000000.0,894580000.0,209210000.0,152780000.0,349090000.0,918700000.0,1060400000.0,702710000.0,66811000.0,150990000.0,1351300000.0,37856000000.0,2014900000.0,6798100000.0,7583900000.0,2629900000.0,23788000000.0,4089000000.0,999040000.0,403690000.0,654000000.0,192400000.0,324100000.0,164880000.0,,381850000.0,1568100000.0,272730000.0,54730000000.0,3153500000.0,,273730000.0,10796000000.0,38074000000.0,,4810200000.0,1218000000.0,4204300000.0,964340000.0,6773200000.0,1182000000.0,1019200000.0,7639200000.0,6947900000.0,,1073300000.0,1222400000.0,1940600000.0,12503000000.0,,47162000.0,524000000.0,416430000.0,524370000.0,797150000.0,,6782800000.0,324760000.0,787380000.0,3910300000.0,8292200000.0,6949200000.0,1261600000.0,,806370000.0,192060000.0,596100000.0,468290000.0,1139800000.0,,552110000.0,,3000000000.0,45350000.0,150660000.0,637830000.0,470370000.0,,6429400000.0,30848000000.0,1258300000.0,96334000.0,851670000.0,14862000000.0,,109160000.0,833730000.0,210600000.0,590260000.0,729180000.0,69893000.0,1007300000.0,1363200000.0,3706200000.0,278860000.0,2120200000.0,1128200000.0,2056200000.0,5274400000.0,1013600000.0,112380000.0,8295900000.0,547520000.0,528440000.0,260160000.0,1394800000.0,,20144000000.0,2254600000.0,,155160000.0,,,26649000.0,711420000.0,247040000.0,1974100000.0,17174000000.0,30641000.0,,2632000000.0,2542100000.0,1164700000.0,7673800000.0,905280000.0,22805000000.0,584380000.0,37686000000.0,389370000.0,2098100000.0,1598000000.0,344050000.0,2949200000.0,455320000.0,364610000.0,420620000.0,30031000000.0,124140000.0,10592000000.0,1504700000.0,625740000.0,39678000.0,,1400600000.0,350050000.0,,81160000.0 +2020_06_01_10_22_Q-Exactive-HF-X-Orbitrap_6070,,,55890000000.0,66026000.0,,,136330000.0,1348100000.0,333940000.0,,,,,774230000.0,15708000.0,,14101000.0,223000000.0,17511000.0,,2738800000.0,33226000.0,265190000.0,1074000000.0,105470000.0,1038700000.0,,1419900000.0,101680000.0,149450000.0,201680000.0,,3226700000.0,46769000.0,256830000.0,70726000.0,26526000000.0,,2926400000.0,256470000.0,,221660000.0,3157300000.0,1436500000.0,447650000.0,1338600000.0,,13418000.0,,,23442000.0,73896000.0,248730000.0,1152900000.0,,26541000.0,9956800.0,192110000.0,150070000.0,1806000000.0,,,10494000.0,,,168760000.0,21014000.0,2450700000.0,579230000.0,392560000.0,,24083000.0,6160100.0,89911000.0,67495000.0,,145090000.0,78597000.0,11916000.0,2710000000.0,242730000.0,17036000.0,33516000.0,,406860000.0,38678000.0,,,,70205000.0,16756000.0,8879300.0,50488000.0,108430000.0,,24833000.0,169780000.0,,73379000.0,120240000.0,4216700000.0,978530000.0,,74870000.0,,6776500000.0,,321310000.0,,37883000.0,1722900000.0,,58164000.0,54581000.0,51071000.0,290560000.0,9367900.0,508110000.0,1069900000.0,109470000.0,289470000.0,72917000.0,165860000.0,1369600000.0,,39359000.0,129480000.0,697060000.0,,302960000.0,,44198000.0,93360000.0,15622000.0,,22107000.0,139290000.0,,355490000.0,,,,,2113400000.0,,,42548000.0,,105980000.0,,234350000.0,86918000.0,66350000.0,526930000.0,33086000.0,345890000.0,284960000.0,10174000.0,1879200000.0,18745000.0,2071400000.0,54665000.0,258190000.0,33332000.0,,,107370000.0,113240000.0,147700000.0,149250000.0,480610000.0,622070000.0,37678000.0,,57058000.0,67140000.0,2266000000.0,10759000.0,579520000.0,,7364100.0,38069000.0,87959000.0,154820000.0,,730270000.0,63078000.0,2011300000.0,2249300000.0,12072000.0,340160000.0,213220000.0,,1412700000.0,60432000.0,,674710000.0,758230000.0,374700000.0,,615360000.0,36316000.0,2107000000.0,,4793700000.0,,,245180000.0,83886000.0,,89246000.0,,2524700000.0,82512000.0,35134000.0,,1504500000.0,2406900000.0,1777400000.0,13530000.0,,641680000.0,,93636000.0,48786000000.0,89755000.0,,55161000.0,,,38704000.0,1159100000.0,154210000.0,,,452070000.0,,537160000.0,13544000.0,,,,325880000.0,160020000.0,200950000.0,253720000.0,216480000.0,15458000000.0,223840000.0,8788500000.0,,,13790000.0,59369000.0,31543000.0,,639690000.0,10075000000.0,,149390000.0,489730000.0,,,4400100000.0,847190000.0,42061000.0,,249040000.0,72017000.0,4738600000.0,212800000.0,301520000.0,47335000000.0,4022100000.0,133350000.0,51544000.0,3334900000.0,1160000000.0,155570000.0,,155240000.0,75034000.0,2566100000.0,200550000.0,78491000.0,,,127890000.0,1805700000.0,892320000.0,664220000.0,17718000.0,12492000000.0,,232540000.0,3300700000.0,,975950000.0,,30277000.0,1823400000.0,59907000.0,,349990000.0,150680000.0,127350000.0,743800000.0,10079000000.0,75540000.0,,,20424000.0,,84682000.0,,,318940000.0,317440000.0,5059900000.0,247910000.0,,1246700000.0,605220000.0,9363400000.0,8443600000.0,,108050000.0,,32696000.0,60065000.0,56470000.0,50902000.0,,268120000.0,,11433000000.0,343410000.0,,,2012700000.0,5600500000.0,,2945700000.0,372320000.0,496220000.0,933480000.0,549400000.0,302800000.0,109320000.0,5145400000.0,1248500000.0,217080000.0,65650000.0,67745000.0,200580000.0,3878700000.0,,36956000.0,32036000.0,31526000.0,107250000.0,443910000.0,,2545400000.0,56806000.0,67039000.0,3310800000.0,1683200000.0,450970000.0,98504000.0,130670000.0,2960500000.0,1052700000.0,137210000.0,,241830000.0,,45750000.0,,291560000.0,25862000.0,,,469130000.0,2046600000.0,3024700000.0,11440000000.0,382140000.0,,46063000.0,10572000000.0,,118990000.0,48306000.0,90164000.0,,77368000.0,49055000.0,,257920000.0,108340000.0,,35836000.0,247030000.0,502560000.0,410450000.0,126280000.0,28494000.0,468510000.0,,,120000000.0,140270000.0,,18368000000.0,243280000.0,,,17227000.0,45668000.0,248170000.0,59534000.0,,96251000.0,7579300000.0,,143470000.0,154910000.0,117480000.0,,516370000.0,,11749000000.0,93313000.0,7579200000.0,,535680000.0,357460000.0,33023000.0,4538900000.0,70898000.0,31142000.0,,3462500000.0,,987000000.0,490890000.0,,,,68818000.0,25847000.0,39407000.0,35227000.0 +2020_06_01_15_41_Q-Exactive-HF-X-Orbitrap_6070,,54655000.0,91447000000.0,88627000.0,67107000.0,,432280000.0,2003200000.0,1809000000.0,,,113970000.0,61425000.0,1187900000.0,74170000.0,23177000.0,22471000.0,191420000.0,54614000.0,93136000.0,3666400000.0,93590000.0,,2460700000.0,444540000.0,2799600000.0,24352000.0,2504000000.0,672920000.0,194690000.0,330060000.0,15771000.0,8175400000.0,55135000.0,572860000.0,300900000.0,49982000000.0,30691000.0,3745500000.0,133420000.0,118620000.0,630460000.0,3931000000.0,2685300000.0,781040000.0,2474900000.0,,,,,,27344000000.0,465120000.0,2540700000.0,,,,354080000.0,53343000.0,8741500000.0,,86055000.0,9706700.0,,160120000.0,451590000.0,,5561500000.0,673270000.0,1012500000.0,,,,184470000.0,,80588000.0,281420000.0,81121000.0,,3008000000.0,274610000.0,,,,384310000.0,69754000.0,,62063000.0,,152950000.0,,,,67785000.0,,434230000.0,158540000.0,,460170000.0,214760000.0,7158600000.0,1595800000.0,934630000.0,179700000.0,,10521000000.0,,,,115820000.0,4423700000.0,,74640000.0,66143000.0,89312000.0,,,1207200000.0,640700000.0,300880000.0,886220000.0,578980000.0,254810000.0,2833200000.0,,85345000.0,,1645500000.0,,456900000.0,,63657000.0,204510000.0,26018000.0,,122580000.0,265070000.0,22577000000.0,825990000.0,35656000.0,29577000.0,,57637000.0,3318900000.0,,,190920000.0,67961000.0,45050000.0,,556100000.0,,84590000.0,667910000.0,674820000.0,353850000.0,285440000.0,71969000.0,3912400000.0,22163000.0,3571000000.0,,362770000.0,222850000.0,40673000.0,164480000.0,159210000.0,205210000.0,46317000.0,209910000.0,1054600000.0,751010000.0,,,82409000.0,,3312200000.0,254240000.0,751260000.0,103210000.0,25285000.0,37017000.0,,450890000.0,,1352500000.0,78802000.0,3504800000.0,3821000000.0,216780000.0,361780000.0,464200000.0,,2053800000.0,107420000.0,,2814500000.0,1145300000.0,1091700000.0,,1175100000.0,105800000.0,2566200000.0,,6833900000.0,103460000.0,,383310000.0,35300000.0,,118010000.0,,5914900000.0,,134170000.0,,2293400000.0,3403900000.0,3682300000.0,100520000.0,,1022300000.0,,154840000.0,57897000000.0,111310000.0,,14658000.0,,,245800000.0,1608400000.0,462900000.0,,,697120000.0,,1042500000.0,34572000.0,61133000.0,11907000.0,,1374200000.0,351910000.0,521210000.0,365140000.0,510680000.0,33721000000.0,704310000.0,21510000000.0,57803000.0,,,77518000.0,,119990000.0,959620000.0,18065000000.0,,406460000.0,758590000.0,,,8470300000.0,2063500000.0,62815000.0,,,164290000.0,9705600000.0,796180000.0,408980000.0,80951000000.0,6573500000.0,258120000.0,,6598500000.0,2994300000.0,283620000.0,,446850000.0,191870000.0,4196700000.0,117810000.0,,,,282020000.0,2194200000.0,901790000.0,717750000.0,32743000.0,29178000000.0,,217480000.0,7467000000.0,,2340800000.0,,37414000.0,3238000000.0,171310000.0,,277440000.0,611840000.0,214670000.0,1345700000.0,19914000000.0,193470000.0,,,72760000.0,,110120000.0,219090000.0,,436480000.0,890290000.0,16739000000.0,735690000.0,,3664400000.0,1585900000.0,9266600000.0,15962000000.0,,231950000.0,,92825000.0,131590000.0,121790000.0,166280000.0,,552920000.0,109560000.0,23822000000.0,1064000000.0,,,3331800000.0,10382000000.0,,3906900000.0,409320000.0,939440000.0,1112800000.0,1200200000.0,591440000.0,267420000.0,6823100000.0,1505300000.0,458900000.0,89570000.0,791220000.0,537760000.0,7345900000.0,,336280000.0,55059000.0,83858000.0,129240000.0,985200000.0,,6535300000.0,84085000.0,202090000.0,4354100000.0,3636600000.0,1135300000.0,,379980000.0,5021600000.0,1625900000.0,353730000.0,,387350000.0,,,88513000.0,683060000.0,28750000.0,,,213550000.0,,2645900000.0,16008000000.0,612290000.0,,240670000.0,15447000000.0,,143620000.0,85581000.0,141510000.0,,448200000.0,,34153000.0,675760000.0,462530000.0,,126840000.0,308450000.0,930350000.0,555180000.0,246580000.0,,763020000.0,350890000.0,31272000.0,153200000.0,337310000.0,,24099000000.0,233100000.0,172810000.0,,,93631000.0,830770000.0,192600000.0,93967000.0,321910000.0,11947000000.0,,,251150000.0,417060000.0,151840000.0,1123400000.0,,23619000000.0,75746000.0,9311700000.0,,142750000.0,1340200000.0,276920000.0,6410000000.0,101930000.0,,,6104800000.0,,1910800000.0,1441300000.0,201690000.0,,993580000.0,136270000.0,,67984000.0,139900000.0 +2020_06_02_09_41_Q-Exactive-HF-X-Orbitrap_6070,,,54795000000.0,505350000.0,,,,1422800000.0,611290000.0,112210000.0,77665000.0,,154770000.0,1418800000.0,252810000.0,158600000.0,,567720000.0,,,2686500000.0,,,2941200000.0,631590000.0,1514900000.0,,1049100000.0,166030000.0,86645000.0,159910000.0,97610000.0,7707400000.0,,46104000.0,259910000.0,45412000000.0,56571000.0,6773800000.0,,899030000.0,308030000.0,4596700000.0,1517500000.0,661300000.0,2436800000.0,166120000.0,124390000.0,1371900000.0,206270000.0,67845000.0,,1191700000.0,793560000.0,,66906000.0,155990000.0,1358800000.0,600570000.0,5935400000.0,221630000.0,239810000.0,,207150000.0,,,47434000.0,6237200000.0,,1346800000.0,145400000.0,71843000.0,13672000.0,339080000.0,446410000.0,,2550000000.0,450820000.0,201960000.0,4131700000.0,487220000.0,185410000.0,442290000.0,,,120430000.0,150590000.0,273140000.0,341760000.0,63893000.0,81216000.0,35455000.0,139960000.0,169770000.0,12002000.0,77102000.0,340140000.0,31760000.0,413620000.0,139110000.0,6530400000.0,2394800000.0,1778000000.0,,35376000.0,11337000000.0,,575550000.0,,88353000.0,928010000.0,564840000.0,,,,103780000.0,,418330000.0,1735300000.0,182630000.0,850280000.0,1011200000.0,158620000.0,3305500000.0,191130000.0,,49056000.0,1482400000.0,,678560000.0,66879000.0,105160000.0,139160000.0,29009000.0,46447000.0,8382700.0,345970000.0,13084000000.0,,39240000.0,1522600000.0,691590000.0,102740000.0,4334800000.0,30596000.0,17413000.0,174660000.0,31880000.0,152250000.0,,647800000.0,,119860000.0,80722000.0,484990000.0,1472700000.0,436810000.0,207080000.0,1435100000.0,346070000.0,3700600000.0,,679000000.0,185970000.0,139320000.0,248950000.0,375050000.0,266060000.0,295540000.0,1185000000.0,368650000.0,146270000.0,25266000.0,28334000.0,48993000.0,,1766100000.0,228380000.0,716300000.0,,211090000.0,272370000.0,368770000.0,887160000.0,,4544900000.0,95955000.0,5551200000.0,1991800000.0,140140000.0,518930000.0,351720000.0,,2057900000.0,47339000.0,,3775000000.0,1190900000.0,473080000.0,,791520000.0,317410000.0,1366700000.0,17431000.0,19727000000.0,87242000.0,300830000.0,229720000.0,117020000.0,,204210000.0,32253000.0,3385000000.0,,579770000.0,1096900000.0,,1695600000.0,2296000000.0,65880000.0,190270000.0,2432200000.0,168370000.0,87852000.0,32616000000.0,135580000.0,32068000.0,50445000.0,,,,1013200000.0,191650000.0,149300000.0,,,100610000.0,571850000.0,139910000.0,260800000.0,359110000.0,,1619800000.0,128320000.0,732750000.0,,312010000.0,18393000000.0,2322500000.0,16502000000.0,289710000.0,187210000.0,,279280000.0,491830000.0,211740000.0,1227500000.0,7210600000.0,46571000.0,322460000.0,761930000.0,41030000.0,11656000.0,6148300000.0,3263100000.0,,58675000.0,256410000.0,445520000.0,7725400000.0,667910000.0,783490000.0,28803000000.0,8431000000.0,822570000.0,301180000.0,4292600000.0,2447500000.0,665450000.0,,379840000.0,317070000.0,3712100000.0,736290000.0,976500000.0,67860000.0,,340230000.0,687760000.0,1742200000.0,756040000.0,33531000.0,19729000000.0,,1102100000.0,13414000000.0,,3696900000.0,18533000.0,63805000.0,3401300000.0,56421000.0,115990000.0,1013400000.0,292290000.0,341020000.0,,,342070000.0,108570000.0,40504000.0,36543000.0,328370000.0,244230000.0,234160000.0,26040000.0,57531000.0,526260000.0,11838000000.0,508580000.0,590530000.0,3672600000.0,1021100000.0,8795800000.0,,294560000.0,95530000.0,328490000.0,,131850000.0,,,121930000.0,517180000.0,285310000.0,21658000000.0,1165500000.0,131530000.0,66890000.0,2920200000.0,15280000000.0,,2148800000.0,392260000.0,1362500000.0,731290000.0,2627100000.0,624790000.0,468200000.0,2684800000.0,2624000000.0,,323760000.0,545850000.0,600800000.0,4989800000.0,,,195110000.0,55007000.0,71862000.0,375480000.0,,3254800000.0,65776000.0,467850000.0,2090900000.0,3522500000.0,2668100000.0,523770000.0,,662880000.0,364060000.0,159080000.0,233300000.0,417000000.0,,,,1302500000.0,20339000.0,71377000.0,185190000.0,318070000.0,,3192700000.0,13410000000.0,634830000.0,,203680000.0,7460000000.0,,,289120000.0,90977000.0,181540000.0,141860000.0,,282790000.0,659420000.0,1637000000.0,67166000.0,884350000.0,616300000.0,1144600000.0,2002200000.0,286780000.0,129810000.0,3445500000.0,299110000.0,105040000.0,,414140000.0,,15866000000.0,1173000000.0,,13291000.0,,,,198080000.0,69451000.0,528950000.0,7501200000.0,18721000.0,,707700000.0,841990000.0,,4144600000.0,319360000.0,11734000000.0,216610000.0,15484000000.0,72631000.0,1031500000.0,993740000.0,242940000.0,703540000.0,207100000.0,,153170000.0,11233000000.0,73347000.0,4184000000.0,293420000.0,135630000.0,42044000.0,,,52246000.0,,121840000.0 From 2bb3d4daeeabab87ef0af895ed012b8e8a0cc338 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Thu, 16 Nov 2023 17:51:27 +0100 Subject: [PATCH 51/70] :art: update metadata remove warnings thrown by papermill --- project/01_0_split_data.ipynb | 2 -- 1 file changed, 2 deletions(-) diff --git a/project/01_0_split_data.ipynb b/project/01_0_split_data.ipynb index 753ce25a6..b4949548c 100644 --- a/project/01_0_split_data.ipynb +++ b/project/01_0_split_data.ipynb @@ -1163,7 +1163,6 @@ }, { "cell_type": "markdown", - "id": "b364b6a4", "metadata": {}, "source": [ "Some tools require at least 4 observation in the training data,\n", @@ -1177,7 +1176,6 @@ { "cell_type": "code", "execution_count": null, - "id": "39b38235", "metadata": {}, "outputs": [], "source": [ From 9456d9116f29177be3adebf62efa3eef1737c2ec Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Thu, 16 Nov 2023 17:53:53 +0100 Subject: [PATCH 52/70] :bug: add method and set defaults from grid search - update defaults to results from small grid search (smallest of top 3) --- .../config/single_dev_dataset/evidence/config.yaml | 12 ++++++------ .../config/single_dev_dataset/peptides/config.yaml | 12 ++++++------ .../single_dev_dataset/peptides_N50/train_DAE.yaml | 4 ++-- .../single_dev_dataset/peptides_N50/train_VAE.yaml | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/project/config/single_dev_dataset/evidence/config.yaml b/project/config/single_dev_dataset/evidence/config.yaml index fb86e8d9a..abda49a9b 100644 --- a/project/config/single_dev_dataset/evidence/config.yaml +++ b/project/config/single_dev_dataset/evidence/config.yaml @@ -5,18 +5,18 @@ folder_experiment: runs/dev_dataset_large/evidence fn_rawfile_metadata: data/dev_datasets/df_intensities_evidence_long/metadata.csv cuda: False models: - - Median - - CF - - DAE - - VAE - - KNN + - Median + - CF + - DAE + - VAE + - KNN NAGuideR_methods: # - BPCA # stopped after 24h - COLMEDIAN - IMPSEQ - IMPSEQROB # - IRM # stopped after 24h - # - KNN_IMPUTE + - KNN_IMPUTE # - LLS # error # - MICE-CART # stopped after 24h # - MICE-NORM # stopped after 24h diff --git a/project/config/single_dev_dataset/peptides/config.yaml b/project/config/single_dev_dataset/peptides/config.yaml index caf67d87e..102e77741 100644 --- a/project/config/single_dev_dataset/peptides/config.yaml +++ b/project/config/single_dev_dataset/peptides/config.yaml @@ -5,18 +5,18 @@ folder_experiment: runs/dev_dataset_large/peptides fn_rawfile_metadata: data/dev_datasets/df_intensities_peptides_long/metadata.csv cuda: False models: - - Median # ~ 1:20 min - - CF # ~ 12:07 min - - DAE # 4:36 mins - - VAE # ~ 3:32 min - - KNN # ~ 2:20 min + - Median # ~ 1:20 min + - CF # ~ 12:07 min + - DAE # 4:36 mins + - VAE # ~ 3:32 min + - KNN # ~ 2:20 min NAGuideR_methods: # - BPCA # stopped after 24h - COLMEDIAN - IMPSEQ - IMPSEQROB # - IRM # stopped after 24h - # - KNN_IMPUTE + - KNN_IMPUTE # - LLS # error # - MICE-CART # stopped after 24h # - MICE-NORM # stopped after 24h diff --git a/project/config/single_dev_dataset/peptides_N50/train_DAE.yaml b/project/config/single_dev_dataset/peptides_N50/train_DAE.yaml index d01114dad..627750d8b 100644 --- a/project/config/single_dev_dataset/peptides_N50/train_DAE.yaml +++ b/project/config/single_dev_dataset/peptides_N50/train_DAE.yaml @@ -1,8 +1,8 @@ file_format: csv -latent_dim: 10 +latent_dim: 75 batch_size: 10 epochs_max: 100 -hidden_layers: "512" +hidden_layers: "256_128" sample_idx_position: 0 cuda: False save_pred_real_na: True \ No newline at end of file diff --git a/project/config/single_dev_dataset/peptides_N50/train_VAE.yaml b/project/config/single_dev_dataset/peptides_N50/train_VAE.yaml index 6239b5bd2..17b98c7fe 100644 --- a/project/config/single_dev_dataset/peptides_N50/train_VAE.yaml +++ b/project/config/single_dev_dataset/peptides_N50/train_VAE.yaml @@ -1,10 +1,10 @@ # models_training: -folder_experiment: runs/example +folder_experiment: runs/example file_format: csv -latent_dim: 25 +latent_dim: 50 batch_size: 10 epochs_max: 100 -hidden_layers: "512_256" +hidden_layers: "256" sample_idx_position: 0 cuda: False save_pred_real_na: True \ No newline at end of file From 1569b97d1934f298549e73cf8e0feb84eaf4ab64 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Thu, 16 Nov 2023 18:41:15 +0100 Subject: [PATCH 53/70] :sparkles: configs for MNAR MCAR experiments document also qsub command and update submission script --- project/bin/create_qsub_commands.py | 39 ++++++++++ project/bin/run_snakemake_cluster.sh | 5 ++ .../single_dev_dataset/mnar_mcar/evi_l.yaml | 76 ++++++++++++++++++ .../single_dev_dataset/mnar_mcar/evi_m.yaml | 77 +++++++++++++++++++ .../single_dev_dataset/mnar_mcar/pep_l.yaml | 76 ++++++++++++++++++ .../single_dev_dataset/mnar_mcar/pep_m.yaml | 77 +++++++++++++++++++ .../single_dev_dataset/mnar_mcar/pg_l.yaml | 73 ++++++++++++++++++ .../single_dev_dataset/mnar_mcar/pg_m.yaml | 77 +++++++++++++++++++ 8 files changed, 500 insertions(+) create mode 100755 project/bin/create_qsub_commands.py create mode 100644 project/config/single_dev_dataset/mnar_mcar/evi_l.yaml create mode 100755 project/config/single_dev_dataset/mnar_mcar/evi_m.yaml create mode 100644 project/config/single_dev_dataset/mnar_mcar/pep_l.yaml create mode 100755 project/config/single_dev_dataset/mnar_mcar/pep_m.yaml create mode 100755 project/config/single_dev_dataset/mnar_mcar/pg_l.yaml create mode 100644 project/config/single_dev_dataset/mnar_mcar/pg_m.yaml diff --git a/project/bin/create_qsub_commands.py b/project/bin/create_qsub_commands.py new file mode 100755 index 000000000..d5b2445a9 --- /dev/null +++ b/project/bin/create_qsub_commands.py @@ -0,0 +1,39 @@ +# %% +from itertools import product + +# import subprocess +mnar_mcar = [25, 50, 75] +datasets = ["pg_m", "pg_l", "pep_m", "evi_m", "pep_l", "evi_l"] + +for dataset, perc in product(datasets, mnar_mcar): + print(f"# {dataset = } # {perc = }") + cmd = ( + "qsub bin/run_snakemake_cluster.sh" + f" -N sm_{dataset}_{perc}" + f" -v configfile=config/single_dev_dataset/mnar_mcar/{dataset}.yaml,prefix={dataset}_{perc}," + f"frac_mnar={perc/100:.2f}," + f"config_split=runs/mnar_mcar/{dataset}_{perc}MNAR/01_0_split_data.yaml," + f"config_train=runs/mnar_mcar/{dataset}_{perc}MNAR/train_{{model}}.yaml," + f"folder_experiment=runs/mnar_mcar/{dataset}_{perc}MNAR" + ) + print(cmd) + # subprocess.run(cmd, check=True, shell=True, stdout=subprocess.PIPE) + +# %% [markdown] +# Create local command to run on interactive node +print() +print("#" * 80) +print() +# %% +for dataset, perc in product(datasets, mnar_mcar): + cmd = ( + "snakemake -s workflow/Snakefile_v2" + f" --configfile config/single_dev_dataset/mnar_mcar/{dataset}.yaml" + f" --config frac_mnar={perc/100:.2f}" + f" config_split=runs/mnar_mcar/{dataset}_{perc}MNAR/01_0_split_data.yaml" + f" config_train=runs/mnar_mcar/{dataset}_{perc}MNAR/train_{{model}}.yaml" + f" folder_experiment=runs/mnar_mcar/{dataset}_{perc}MNAR" + " -c1" + ) + print(cmd) +# %% diff --git a/project/bin/run_snakemake_cluster.sh b/project/bin/run_snakemake_cluster.sh index 2b2bb7894..20d24ff2c 100644 --- a/project/bin/run_snakemake_cluster.sh +++ b/project/bin/run_snakemake_cluster.sh @@ -41,16 +41,21 @@ else echo '####################################################################' fi +echo folder_experiment $folder_experiment +echo config_split $config_split +echo config_train $config_train . ~/setup_conda.sh conda activate vaep snakemake -s workflow/Snakefile_v2 --jobs 10 -k -p -c2 --latency-wait 60 --rerun-incomplete \ --configfile $configfile \ +--config frac_mnar=$frac_mnar folder_experiment=$folder_experiment config_split=$config_split config_train=$config_train \ --max-status-checks-per-second 0.1 \ --max-jobs-per-second 1 \ --use-conda \ --default-resources walltime=3600 \ +--rerun-trigger mtime \ --cluster "qsub -l walltime={resources.walltime},nodes=1:ppn={threads},mem={resources.mem_mb}mb"\ " -W group_list=cpr_10006 -A cpr_10006 "\ " -e {params.err} -o {params.out}"\ diff --git a/project/config/single_dev_dataset/mnar_mcar/evi_l.yaml b/project/config/single_dev_dataset/mnar_mcar/evi_l.yaml new file mode 100644 index 000000000..899cd1a59 --- /dev/null +++ b/project/config/single_dev_dataset/mnar_mcar/evi_l.yaml @@ -0,0 +1,76 @@ +# config for Snakefile_v2 +config_split: runs/mnar_mcar/pg_l_50MNAR/01_0_split_data.yaml # ! will be build +config_train: runs/mnar_mcar/pg_l_50MNAR/train_{model}.yaml # ! will be build, should say model_key next +folder_experiment: runs/mnar_mcar/pg_l_50MNAR +frac_mnar: 0.5 +fn_rawfile_metadata: data/dev_datasets/df_intensities_peptides_long/metadata.csv +file_format: csv +split_data: + FN_INTENSITIES: data/dev_datasets/df_intensities_evidence_long/Q_Exactive_HF_X_Orbitrap_6070.pkl + sample_completeness: 0.4 + feat_prevalence: 0.25 + min_RT_time: 120 + index_col: 0 + meta_date_col: Content Creation Date + column_names: null +models: + - Median: + model: Median # needs to set at least one parameter + - CF: + model: CF + file_format: csv + latent_dim: 50 + batch_size: 4096 + epochs_max: 30 + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - DAE: + model: DAE + file_format: csv + latent_dim: 50 + batch_size: 10 + epochs_max: 200 + hidden_layers: "512" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - VAE: + model: VAE + file_format: csv + latent_dim: 25 + batch_size: 10 + epochs_max: 200 + hidden_layers: "512" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - KNN: + model: KNN + neighbors: 3 + file_format: csv +NAGuideR_methods: + # - BPCA # > 24h, killed + - COLMEDIAN + # - GSIMP # > 24h, killed + - IMPSEQ + - IMPSEQROB + # - IRM # > 24h, killed + - KNN_IMPUTE + # - LLS # Error in svd(X): infinite or missing values in 'x' + # - MICE-CART # > 24h, killed + # - MICE-NORM # > 24h, killed + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - MSIMPUTE_MNAR + - PI + - QRILC + # - RF # > 24h, killed + - ROWMEDIAN + # - SEQKNN # error + - SVDMETHOD + # - TRKNN # 24h, killed + - ZERO diff --git a/project/config/single_dev_dataset/mnar_mcar/evi_m.yaml b/project/config/single_dev_dataset/mnar_mcar/evi_m.yaml new file mode 100755 index 000000000..197a882ea --- /dev/null +++ b/project/config/single_dev_dataset/mnar_mcar/evi_m.yaml @@ -0,0 +1,77 @@ +# config for Snakefile_v2 +config_split: runs/mnar_mcar/pg_m_50MNAR/01_0_split_data.yaml # ! will be build +config_train: runs/mnar_mcar/pg_m_50MNAR/train_{model}.yaml # ! will be build, should say model_key next +folder_experiment: runs/mnar_mcar/pg_m_50MNAR +frac_mnar: 0.5 +fn_rawfile_metadata: data/dev_datasets/df_intensities_peptides_long/metadata.csv +file_format: csv +split_data: + FN_INTENSITIES: data/dev_datasets/df_intensities_evidence_long/Q_Exactive_HF_X_Orbitrap_6070.pkl + sample_completeness: 0.4 + feat_prevalence: 0.25 + select_N: 50 + min_RT_time: 120 + index_col: 0 + meta_date_col: Content Creation Date + column_names: null +models: + - Median: + model: Median # needs to set at least one parameter + - CF: + model: CF + file_format: csv + latent_dim: 50 + batch_size: 4096 + epochs_max: 30 + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - DAE: + model: DAE + file_format: csv + latent_dim: 25 + batch_size: 10 + epochs_max: 200 + hidden_layers: "256" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - VAE: + model: VAE + file_format: csv + latent_dim: 10 + batch_size: 10 + epochs_max: 200 + hidden_layers: "256" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - KNN: + model: KNN + neighbors: 3 + file_format: csv +NAGuideR_methods: + - BPCA + - COLMEDIAN + # - GSIMP # > 24h, killed + - IMPSEQ + - IMPSEQROB + - IRM # error + - KNN_IMPUTE + # - LLS, # error + - MICE-CART # > 24h, killed + - MICE-NORM # > 24h, killed + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - MSIMPUTE_MNAR + - PI + - QRILC + - RF # > 24h, killed + - ROWMEDIAN + - SEQKNN # error + - SVDMETHOD + - TRKNN # error + - ZERO diff --git a/project/config/single_dev_dataset/mnar_mcar/pep_l.yaml b/project/config/single_dev_dataset/mnar_mcar/pep_l.yaml new file mode 100644 index 000000000..5bbe75364 --- /dev/null +++ b/project/config/single_dev_dataset/mnar_mcar/pep_l.yaml @@ -0,0 +1,76 @@ +# config for Snakefile_v2 +config_split: runs/mnar_mcar/pep_l_50MNAR/01_0_split_data.yaml # ! will be build +config_train: runs/mnar_mcar/pep_l_50MNAR/train_{model}.yaml # ! will be build, should say model_key next +folder_experiment: runs/mnar_mcar/pep_l_50MNAR +frac_mnar: 0.5 +fn_rawfile_metadata: data/dev_datasets/df_intensities_peptides_long/metadata.csv +file_format: csv +split_data: + FN_INTENSITIES: data/dev_datasets/df_intensities_peptides_long/Q_Exactive_HF_X_Orbitrap_6070.pkl + sample_completeness: 0.4 + feat_prevalence: 0.25 + min_RT_time: 120 + index_col: 0 + meta_date_col: Content Creation Date + column_names: null +models: + - Median: + model: Median # needs to set at least one parameter + - CF: + model: CF + file_format: csv + latent_dim: 50 + batch_size: 4096 + epochs_max: 30 + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - DAE: + model: DAE + file_format: csv + latent_dim: 50 + batch_size: 10 + epochs_max: 200 + hidden_layers: "1024" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - VAE: + model: VAE + file_format: csv + latent_dim: 10 + batch_size: 10 + epochs_max: 200 + hidden_layers: "512" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - KNN: + model: KNN + neighbors: 3 + file_format: csv +NAGuideR_methods: + # - BPCA # > 24h, killed + - COLMEDIAN + # - GSIMP # > 24h, killed + - IMPSEQ + - IMPSEQROB + # - IRM # > 24h, killed + - KNN_IMPUTE + # - LLS # error + # - MICE-CART # > 24h, killed + # - MICE-NORM # > 24h, killed + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - MSIMPUTE_MNAR + - PI + - QRILC + # - RF # > 24h, killed + - ROWMEDIAN + # - SEQKNN # Error in x[od, ismiss, drop = FALSE]: subscript out of bounds + - SVDMETHOD + # - TRKNN # > 24h, killed + - ZERO diff --git a/project/config/single_dev_dataset/mnar_mcar/pep_m.yaml b/project/config/single_dev_dataset/mnar_mcar/pep_m.yaml new file mode 100755 index 000000000..b946bcf62 --- /dev/null +++ b/project/config/single_dev_dataset/mnar_mcar/pep_m.yaml @@ -0,0 +1,77 @@ +# config for Snakefile_v2 +config_split: runs/mnar_mcar/pep_m_50MNAR/01_0_split_data.yaml # ! will be build +config_train: runs/mnar_mcar/pep_m_50MNAR/train_{model}.yaml # ! will be build, should say model_key next +folder_experiment: runs/mnar_mcar/pep_m_50MNAR +frac_mnar: 0.5 +fn_rawfile_metadata: data/dev_datasets/df_intensities_peptides_long/metadata.csv +file_format: csv +split_data: + FN_INTENSITIES: data/dev_datasets/df_intensities_peptides_long/Q_Exactive_HF_X_Orbitrap_6070.pkl + sample_completeness: 0.4 + feat_prevalence: 0.25 + select_N: 50 + min_RT_time: 120 + index_col: 0 + meta_date_col: Content Creation Date + column_names: null +models: + - Median: + model: Median # needs to set at least one parameter + - CF: + model: CF + file_format: csv + latent_dim: 50 + batch_size: 4096 + epochs_max: 30 + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - DAE: + model: DAE + file_format: csv + latent_dim: 75 + batch_size: 10 + epochs_max: 200 + hidden_layers: "256_128" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - VAE: + model: VAE + file_format: csv + latent_dim: 50 + batch_size: 10 + epochs_max: 200 + hidden_layers: "256" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - KNN: + model: KNN + neighbors: 3 + file_format: csv +NAGuideR_methods: + - BPCA + - COLMEDIAN + # - GSIMP > 24h, killed + - IMPSEQ + - IMPSEQROB + - IRM + - KNN_IMPUTE + - LLS + - MICE-CART + - MICE-NORM + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - MSIMPUTE_MNAR + - PI + - QRILC + - RF + - ROWMEDIAN + - SEQKNN + - SVDMETHOD + - TRKNN + - ZERO diff --git a/project/config/single_dev_dataset/mnar_mcar/pg_l.yaml b/project/config/single_dev_dataset/mnar_mcar/pg_l.yaml new file mode 100755 index 000000000..9cfb5307c --- /dev/null +++ b/project/config/single_dev_dataset/mnar_mcar/pg_l.yaml @@ -0,0 +1,73 @@ +# config for Snakefile_v2 +config_split: runs/mnar_mcar/pg_l_50MNAR/01_0_split_data.yaml # ! will be build +config_train: runs/mnar_mcar/pg_l_50MNAR/train_{model}.yaml # ! will be build, should say model_key next +folder_experiment: runs/mnar_mcar/pg_l_50MNAR +frac_mnar: 0.5 +fn_rawfile_metadata: data/dev_datasets/df_intensities_proteinGroups_long/metadata.csv +cuda: False +file_format: csv +split_data: + FN_INTENSITIES: data/dev_datasets/df_intensities_proteinGroups_long/Q_Exactive_HF_X_Orbitrap_6070.pkl + sample_completeness: 0.4 + feat_prevalence: 0.25 + min_RT_time: 120 + index_col: 0 + meta_date_col: Content Creation Date +models: + - Median: + model: Median + - CF: # 2min + model: CF + latent_dim: 50 + batch_size: 32768 + epochs_max: 100 + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - DAE: # 2min + model: DAE + latent_dim: 25 + batch_size: 64 + epochs_max: 100 + hidden_layers: "512" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - VAE: # 2min + model: VAE + latent_dim: 25 + batch_size: 64 + epochs_max: 50 + hidden_layers: "512" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - KNN: + model: KNN + neighbors: 3 + file_format: csv +NAGuideR_methods: + - BPCA #6h41min + - COLMEDIAN + # - GSIMP # stopped after 24h + - IMPSEQ # 1min + - IMPSEQROB + - IRM # 7h52min + - KNN_IMPUTE + - LLS + # - MICE-CART # stopped after 24h + # - MICE-NORM # stopped after 24h + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - MSIMPUTE_MNAR + - PI + - QRILC + - RF # 58min + - ROWMEDIAN + # - SEQKNN # Error in x[od, ismiss, drop = FALSE]: subscript out of bounds + - SVDMETHOD # 16min + - TRKNN # 5h38min + - ZERO diff --git a/project/config/single_dev_dataset/mnar_mcar/pg_m.yaml b/project/config/single_dev_dataset/mnar_mcar/pg_m.yaml new file mode 100644 index 000000000..a608a3230 --- /dev/null +++ b/project/config/single_dev_dataset/mnar_mcar/pg_m.yaml @@ -0,0 +1,77 @@ +# config for Snakefile_v2 +config_split: runs/mnar_mcar/pg_m_50MNAR/01_0_split_data.yaml # ! will be build +config_train: runs/mnar_mcar/pg_m_50MNAR/train_{model}.yaml # ! will be build, should say model_key next +folder_experiment: runs/mnar_mcar/pg_m_50MNAR +frac_mnar: 0.5 +fn_rawfile_metadata: data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv +file_format: csv +split_data: + FN_INTENSITIES: data/dev_datasets/HeLa_6070/protein_groups_wide_N50.csv + sample_completeness: 0.4 + feat_prevalence: 0.25 + min_RT_time: 120 + column_names: + - Gene Names + index_col: 0 + meta_date_col: Content Creation Date +models: + - Median: + model: Median # needs to set at least one parameter + - CF: + model: CF + file_format: csv + latent_dim: 50 + batch_size: 4096 + epochs_max: 20 + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - DAE: + model: DAE + file_format: csv + latent_dim: 10 + batch_size: 10 + epochs_max: 200 + hidden_layers: "512" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - VAE: + model: VAE + file_format: csv + latent_dim: 25 + batch_size: 10 + epochs_max: 200 + hidden_layers: "512_256" + sample_idx_position: 0 + cuda: False + save_pred_real_na: True + - KNN: + model: KNN + neighbors: 3 + file_format: csv +NAGuideR_methods: + - BPCA + - COLMEDIAN + - GSIMP + - IMPSEQ + - IMPSEQROB + - IRM + - KNN_IMPUTE + - LLS + - MICE-CART + - MICE-NORM + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - MSIMPUTE_MNAR + - PI + - QRILC + - RF + - ROWMEDIAN + - SEQKNN + - SVDMETHOD + - TRKNN + - ZERO From 35322b3bf90bfca2b8060efd7cd4a8a0f0ad0d3a Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Thu, 16 Nov 2023 18:42:35 +0100 Subject: [PATCH 54/70] :art::construction: improve plots for Figure 2 (add more models) - needs to be completed and cleaned-up --- project/03_2_best_models_comparison_fig2.py | 4 ++-- vaep/plotting/defaults.py | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/project/03_2_best_models_comparison_fig2.py b/project/03_2_best_models_comparison_fig2.py index f5e66baca..97c3e07e3 100644 --- a/project/03_2_best_models_comparison_fig2.py +++ b/project/03_2_best_models_comparison_fig2.py @@ -90,7 +90,7 @@ metrics = metrics.loc[ORDER_DATA, ORDER_MODELS] plt.rcParams['figure.figsize'] = [4.0, 2.0] -matplotlib.rcParams.update({'font.size': 5}) +matplotlib.rcParams.update({'font.size': 6}) ax = (metrics .plot @@ -99,7 +99,7 @@ ylabel=f"{METRIC} (log2 intensities)", color=COLORS_TO_USE_MAPPTING, width=.85, - fontsize=8 + fontsize=7 )) ax = vaep.plotting.add_height_to_barplot(ax, size=5) diff --git a/vaep/plotting/defaults.py b/vaep/plotting/defaults.py index 637f0815c..ca3d7851f 100644 --- a/vaep/plotting/defaults.py +++ b/vaep/plotting/defaults.py @@ -17,11 +17,21 @@ 'None': sns.color_palette()[7], 'BPCA': sns.color_palette()[8], 'MICE-CART': sns.color_palette()[9], - 'SEQKNN': sns.color_palette()[6], - 'MICE-NORM': sns.color_palette()[1], + } # other_colors = sns.color_palette()[8:] other_colors = sns.color_palette("husl", 20) +color_model_mapping['IMPSEQ'] = other_colors[0] +color_model_mapping['IMPSEQROB'] = other_colors[1] +color_model_mapping['MICE-NORM'] = other_colors[2] +color_model_mapping['SEQKNN'] = other_colors[3] +color_model_mapping['QRILC'] = other_colors[4] +color_model_mapping['GSIMP'] = other_colors[5] +color_model_mapping['MSIMPUTE'] = other_colors[6] +color_model_mapping['MSIMPUTE_MNAR'] = other_colors[7] +color_model_mapping['TRKNN'] = other_colors[8] +color_model_mapping['SVDMETHOD'] = other_colors[9] +other_colors = sns.color_palette()[10:] def assign_colors(models): From 0b0d747ea8ac09af67a38ff0a40f8b8e8f34e728 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 17 Nov 2023 09:24:27 +0100 Subject: [PATCH 55/70] :bug: fix remaining colors, test --- vaep/plotting/defaults.py | 2 +- vaep/tests/plotting/test_defaults.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 vaep/tests/plotting/test_defaults.py diff --git a/vaep/plotting/defaults.py b/vaep/plotting/defaults.py index ca3d7851f..d6e2b5b81 100644 --- a/vaep/plotting/defaults.py +++ b/vaep/plotting/defaults.py @@ -31,7 +31,7 @@ color_model_mapping['MSIMPUTE_MNAR'] = other_colors[7] color_model_mapping['TRKNN'] = other_colors[8] color_model_mapping['SVDMETHOD'] = other_colors[9] -other_colors = sns.color_palette()[10:] +other_colors = other_colors[10:] def assign_colors(models): diff --git a/vaep/tests/plotting/test_defaults.py b/vaep/tests/plotting/test_defaults.py new file mode 100644 index 000000000..086a1df63 --- /dev/null +++ b/vaep/tests/plotting/test_defaults.py @@ -0,0 +1,9 @@ +from vaep.plotting.defaults import assign_colors + + +def test_assign_colors(): + expected = [(0.8392156862745098, 0.15294117647058825, 0.1568627450980392), + (0.17254901960784313, 0.6274509803921569, 0.17254901960784313), + (0.21044753832183283, 0.6773105080456748, 0.6433941168468681)] + assigned = assign_colors(['DAE', 'CF', 'Test']) + assert assigned == expected From 89046b42432e9a6e2c5ae0312e3d134263a49a7a Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Fri, 17 Nov 2023 13:57:16 +0100 Subject: [PATCH 56/70] :bug: don't train with too small batches - rather "bigger" batches with more training steps - update Fig. 2 plots generation to 25MNAR --- .../03_2_best_models_comparison_fig2.ipynb | 26 ++++++++++--------- project/03_2_best_models_comparison_fig2.py | 24 +++++++++-------- .../single_dev_dataset/mnar_mcar/evi_m.yaml | 5 ++-- .../single_dev_dataset/mnar_mcar/pep_m.yaml | 5 ++-- .../single_dev_dataset/mnar_mcar/pg_m.yaml | 5 ++-- 5 files changed, 36 insertions(+), 29 deletions(-) diff --git a/project/03_2_best_models_comparison_fig2.ipynb b/project/03_2_best_models_comparison_fig2.ipynb index ef70b394c..199587add 100644 --- a/project/03_2_best_models_comparison_fig2.ipynb +++ b/project/03_2_best_models_comparison_fig2.ipynb @@ -34,11 +34,12 @@ "outputs": [], "source": [ "# parameters\n", - "FOLDER = Path('runs/dev_dataset_large/')\n", + "FOLDER = Path('runs/mnar_mcar/')\n", + "SIZE = 'l'\n", "files_in = {\n", - " 'protein groups': FOLDER / 'proteinGroups/figures/performance_test.csv',\n", - " 'peptides': FOLDER / 'peptides/figures/performance_test.csv',\n", - " 'precursors': FOLDER / 'evidence/figures/performance_test.csv'\n", + " 'protein groups': FOLDER / 'pg_l_25MNAR/figures/2_1_performance_test.csv',\n", + " 'peptides': FOLDER / 'pep_l_25MNAR/figures/2_1_performance_test.csv',\n", + " 'precursors': FOLDER / 'evi_l_25MNAR/figures/2_1_performance_test.csv'\n", "}" ] }, @@ -49,11 +50,12 @@ "metadata": {}, "outputs": [], "source": [ - "FOLDER = Path('runs/dev_dataset_small/')\n", + "FOLDER = Path('runs/mnar_mcar/')\n", + "SIZE = 'm'\n", "files_in = {\n", - " 'protein groups': FOLDER / 'proteinGroups_N50/figures/performance_test.csv',\n", - " 'peptides': FOLDER / 'peptides_N50/figures/performance_test.csv',\n", - " 'precursors': FOLDER / 'evidence_N50/figures/performance_test.csv'\n", + " 'protein groups': FOLDER / 'pg_m_25MNAR/figures/2_1_performance_test.csv',\n", + " 'peptides': FOLDER / 'pep_m_25MNAR/figures/2_1_performance_test.csv',\n", + " 'precursors': FOLDER / 'evi_m_25MNAR/figures/2_1_performance_test.csv'\n", "}" ] }, @@ -134,13 +136,13 @@ }, "outputs": [], "source": [ - "fname = FOLDER / 'best_models_1_test_mpl.pdf'\n", + "fname = FOLDER / f'best_models_{SIZE}_test_mpl.pdf'\n", "metrics = df['metric_value'].unstack('model')\n", "ORDER_MODELS = metrics.mean().sort_values().index.to_list()\n", "metrics = metrics.loc[ORDER_DATA, ORDER_MODELS]\n", "\n", "plt.rcParams['figure.figsize'] = [4.0, 2.0]\n", - "matplotlib.rcParams.update({'font.size': 5})\n", + "matplotlib.rcParams.update({'font.size': 6})\n", "\n", "ax = (metrics\n", " .plot\n", @@ -149,7 +151,7 @@ " ylabel=f\"{METRIC} (log2 intensities)\",\n", " color=COLORS_TO_USE_MAPPTING,\n", " width=.85,\n", - " fontsize=8\n", + " fontsize=7\n", " ))\n", "\n", "ax = vaep.plotting.add_height_to_barplot(ax, size=5)\n", @@ -230,7 +232,7 @@ "metadata": {}, "outputs": [], "source": [ - "fname = FOLDER / 'performance_summary.xlsx'\n", + "fname = FOLDER / f'performance_summary_{SIZE}.xlsx'\n", "perf.to_excel(fname)\n", "fname.as_posix()" ] diff --git a/project/03_2_best_models_comparison_fig2.py b/project/03_2_best_models_comparison_fig2.py index 97c3e07e3..55c5a0d5c 100644 --- a/project/03_2_best_models_comparison_fig2.py +++ b/project/03_2_best_models_comparison_fig2.py @@ -6,7 +6,7 @@ # extension: .py # format_name: percent # format_version: '1.3' -# jupytext_version: 1.15.0 +# jupytext_version: 1.15.2 # kernelspec: # display_name: Python 3 # language: python @@ -33,19 +33,21 @@ # %% # parameters -FOLDER = Path('runs/dev_dataset_large/') +FOLDER = Path('runs/mnar_mcar/') +SIZE = 'l' files_in = { - 'protein groups': FOLDER / 'proteinGroups/figures/performance_test.csv', - 'peptides': FOLDER / 'peptides/figures/performance_test.csv', - 'precursors': FOLDER / 'evidence/figures/performance_test.csv' + 'protein groups': FOLDER / 'pg_l_25MNAR/figures/2_1_performance_test.csv', + 'peptides': FOLDER / 'pep_l_25MNAR/figures/2_1_performance_test.csv', + 'precursors': FOLDER / 'evi_l_25MNAR/figures/2_1_performance_test.csv' } # %% -FOLDER = Path('runs/dev_dataset_small/') +FOLDER = Path('runs/mnar_mcar/') +SIZE = 'm' files_in = { - 'protein groups': FOLDER / 'proteinGroups_N50/figures/performance_test.csv', - 'peptides': FOLDER / 'peptides_N50/figures/performance_test.csv', - 'precursors': FOLDER / 'evidence_N50/figures/performance_test.csv' + 'protein groups': FOLDER / 'pg_m_25MNAR/figures/2_1_performance_test.csv', + 'peptides': FOLDER / 'pep_m_25MNAR/figures/2_1_performance_test.csv', + 'precursors': FOLDER / 'evi_m_25MNAR/figures/2_1_performance_test.csv' } # %% @@ -84,7 +86,7 @@ df # %% -fname = FOLDER / 'best_models_1_test_mpl.pdf' +fname = FOLDER / f'best_models_{SIZE}_test_mpl.pdf' metrics = df['metric_value'].unstack('model') ORDER_MODELS = metrics.mean().sort_values().index.to_list() metrics = metrics.loc[ORDER_DATA, ORDER_MODELS] @@ -148,6 +150,6 @@ perf # %% -fname = FOLDER / 'performance_summary.xlsx' +fname = FOLDER / f'performance_summary_{SIZE}.xlsx' perf.to_excel(fname) fname.as_posix() diff --git a/project/config/single_dev_dataset/mnar_mcar/evi_m.yaml b/project/config/single_dev_dataset/mnar_mcar/evi_m.yaml index 197a882ea..3de82f1dc 100755 --- a/project/config/single_dev_dataset/mnar_mcar/evi_m.yaml +++ b/project/config/single_dev_dataset/mnar_mcar/evi_m.yaml @@ -30,7 +30,8 @@ models: model: DAE file_format: csv latent_dim: 25 - batch_size: 10 + batch_size: 25 + patience: 50 epochs_max: 200 hidden_layers: "256" sample_idx_position: 0 @@ -40,7 +41,7 @@ models: model: VAE file_format: csv latent_dim: 10 - batch_size: 10 + batch_size: 25 epochs_max: 200 hidden_layers: "256" sample_idx_position: 0 diff --git a/project/config/single_dev_dataset/mnar_mcar/pep_m.yaml b/project/config/single_dev_dataset/mnar_mcar/pep_m.yaml index b946bcf62..cfdd672fd 100755 --- a/project/config/single_dev_dataset/mnar_mcar/pep_m.yaml +++ b/project/config/single_dev_dataset/mnar_mcar/pep_m.yaml @@ -30,7 +30,8 @@ models: model: DAE file_format: csv latent_dim: 75 - batch_size: 10 + batch_size: 25 + patience: 50 epochs_max: 200 hidden_layers: "256_128" sample_idx_position: 0 @@ -40,7 +41,7 @@ models: model: VAE file_format: csv latent_dim: 50 - batch_size: 10 + batch_size: 25 epochs_max: 200 hidden_layers: "256" sample_idx_position: 0 diff --git a/project/config/single_dev_dataset/mnar_mcar/pg_m.yaml b/project/config/single_dev_dataset/mnar_mcar/pg_m.yaml index a608a3230..b484276c5 100644 --- a/project/config/single_dev_dataset/mnar_mcar/pg_m.yaml +++ b/project/config/single_dev_dataset/mnar_mcar/pg_m.yaml @@ -30,7 +30,8 @@ models: model: DAE file_format: csv latent_dim: 10 - batch_size: 10 + batch_size: 25 + patience: 50 epochs_max: 200 hidden_layers: "512" sample_idx_position: 0 @@ -40,7 +41,7 @@ models: model: VAE file_format: csv latent_dim: 25 - batch_size: 10 + batch_size: 25 epochs_max: 200 hidden_layers: "512_256" sample_idx_position: 0 From c9e00e40daff12eeeb199aaecd7062cf1b9edb3c Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 26 Nov 2023 12:23:35 +0100 Subject: [PATCH 57/70] :art::wrench: improve swarmplots, add methods in ALD comp. --- project/10_4_ald_compare_single_pg.ipynb | 76 +++---------------- project/10_4_ald_compare_single_pg.py | 64 ++-------------- .../plasma/proteinGroups/comparison.yaml | 17 +++-- .../plasma/proteinGroups/config.yaml | 33 ++++---- 4 files changed, 42 insertions(+), 148 deletions(-) diff --git a/project/10_4_ald_compare_single_pg.ipynb b/project/10_4_ald_compare_single_pg.ipynb index 80ea04a41..0b60a92c0 100644 --- a/project/10_4_ald_compare_single_pg.ipynb +++ b/project/10_4_ald_compare_single_pg.ipynb @@ -20,6 +20,7 @@ "source": [ "from pathlib import Path\n", "\n", + "import logging\n", "import matplotlib.pyplot as plt\n", "import pandas as pd\n", "\n", @@ -32,10 +33,10 @@ "import vaep.imputation\n", "\n", "logger = vaep.logging.setup_nb_logger()\n", - "\n", + "logging.getLogger('fontTools').setLevel(logging.WARNING)\n", "\n", "plt.rcParams['figure.figsize'] = [4, 2.5] # [16.0, 7.0] , [4, 3]\n", - "vaep.plotting.make_large_descriptors(5)" + "vaep.plotting.make_large_descriptors(7)" ] }, { @@ -580,7 +581,9 @@ "cell_type": "code", "execution_count": null, "id": "f813f693", - "metadata": {}, + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], "source": [ "min_y_int, max_y_int = vaep.plotting.data.get_min_max_iterable(\n", @@ -592,66 +595,6 @@ "min_max, target_name" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "d03628eb", - "metadata": {}, - "outputs": [], - "source": [ - "for idx in feat_sel:\n", - " fig, ax = plt.subplots()\n", - "\n", - " feat_observed = data[idx].dropna()\n", - "\n", - " label_template = '{method} (N={n:,d}, q={q:.3f})'\n", - " # observed data\n", - " vaep.plotting.data.plot_histogram_intensities(\n", - " feat_observed,\n", - " ax=ax,\n", - " min_max=min_max,\n", - " label=label_template.format(method='measured',\n", - " n=len(feat_observed),\n", - " q=float(qvalues.loc[idx, ('None', 'qvalue')])),\n", - " color='grey',\n", - " alpha=0.6)\n", - "\n", - " # all models\n", - " for i, method in enumerate(model_keys):\n", - " try:\n", - " pred = pred_real_na.loc[pd.IndexSlice[:, idx], method].dropna()\n", - " if len(pred) == 0:\n", - " # in case no values was imputed -> qvalue is as based on measured\n", - " label = label_template.format(method=method,\n", - " n=len(pred),\n", - " q=float(qvalues.loc[idx, ('None', 'qvalue')]\n", - " ))\n", - " else:\n", - " label = label_template.format(method=method,\n", - " n=len(pred),\n", - " q=float(qvalues.loc[idx, (method, 'qvalue')]\n", - " ))\n", - " ax, bins = vaep.plotting.data.plot_histogram_intensities(\n", - " pred,\n", - " ax=ax,\n", - " min_max=min_max,\n", - " label=label,\n", - " color=f'C{i}',\n", - " alpha=0.6)\n", - " except KeyError:\n", - " print(f\"No missing values for {idx}: {method}\")\n", - " continue\n", - " first_pg = idx.split(\";\")[0]\n", - " ax.set_title(\n", - " f'Imputation for protein group {first_pg} with target {target_name} (N= {len(data):,d} samples)')\n", - " ax.set_ylabel('count measurments')\n", - " _ = ax.legend()\n", - " files_out[fname.name] = fname.as_posix()\n", - " vaep.savefig(\n", - " fig, folder / f'{first_pg}_hist.pdf')\n", - " plt.close(fig)" - ] - }, { "cell_type": "markdown", "id": "b9db8a0e", @@ -682,8 +625,8 @@ " tmp_dot.remove()\n", "\n", " feat_observed = data[idx].dropna()\n", - " label_template = '{method} (N={n:,d}, q={q:.3f})'\n", - " key = label_template.format(method='measured',\n", + " label_template = '{method}\\n(N={n:,d}, q={q:.3f})'\n", + " key = label_template.format(method='observed',\n", " n=len(feat_observed),\n", " q=float(qvalues.loc[idx, ('None', 'qvalue')])\n", " )\n", @@ -726,7 +669,7 @@ " order=groups_order,\n", " dodge=True,\n", " hue=args.target,\n", - " size=1,\n", + " size=2,\n", " ax=ax)\n", " first_pg = idx.split(\";\")[0]\n", " ax.set_title(\n", @@ -747,7 +690,6 @@ " _ = ax.collections[0].set_paths([new_mk])\n", " _ = ax.collections[1].set_paths([new_mk])\n", "\n", - " # import matplotlib.lines as mlines\n", " label_target_0, label_target_1 = ax.collections[-2].get_label(), ax.collections[-1].get_label()\n", " _ = ax.collections[-2].set_label(f'imputed, {label_target_0}')\n", " _ = ax.collections[-1].set_label(f'imputed, {label_target_1}')\n", diff --git a/project/10_4_ald_compare_single_pg.py b/project/10_4_ald_compare_single_pg.py index 925568114..9e50574b9 100644 --- a/project/10_4_ald_compare_single_pg.py +++ b/project/10_4_ald_compare_single_pg.py @@ -21,6 +21,7 @@ # %% from pathlib import Path +import logging import matplotlib.pyplot as plt import pandas as pd @@ -33,10 +34,10 @@ import vaep.imputation logger = vaep.logging.setup_nb_logger() - +logging.getLogger('fontTools').setLevel(logging.WARNING) plt.rcParams['figure.figsize'] = [4, 2.5] # [16.0, 7.0] , [4, 3] -vaep.plotting.make_large_descriptors(5) +vaep.plotting.make_large_descriptors(7) # %% [markdown] # ## Parameters @@ -313,58 +314,6 @@ min_max, target_name -# %% -for idx in feat_sel: - fig, ax = plt.subplots() - - feat_observed = data[idx].dropna() - - label_template = '{method} (N={n:,d}, q={q:.3f})' - # observed data - vaep.plotting.data.plot_histogram_intensities( - feat_observed, - ax=ax, - min_max=min_max, - label=label_template.format(method='measured', - n=len(feat_observed), - q=float(qvalues.loc[idx, ('None', 'qvalue')])), - color='grey', - alpha=0.6) - - # all models - for i, method in enumerate(model_keys): - try: - pred = pred_real_na.loc[pd.IndexSlice[:, idx], method].dropna() - if len(pred) == 0: - # in case no values was imputed -> qvalue is as based on measured - label = label_template.format(method=method, - n=len(pred), - q=float(qvalues.loc[idx, ('None', 'qvalue')] - )) - else: - label = label_template.format(method=method, - n=len(pred), - q=float(qvalues.loc[idx, (method, 'qvalue')] - )) - ax, bins = vaep.plotting.data.plot_histogram_intensities( - pred, - ax=ax, - min_max=min_max, - label=label, - color=f'C{i}', - alpha=0.6) - except KeyError: - print(f"No missing values for {idx}: {method}") - continue - first_pg = idx.split(";")[0] - ax.set_title( - f'Imputation for protein group {first_pg} with target {target_name} (N= {len(data):,d} samples)') - ax.set_ylabel('count measurments') - _ = ax.legend() - files_out[fname.name] = fname.as_posix() - vaep.savefig( - fig, folder / f'{first_pg}_hist.pdf') - plt.close(fig) # %% [markdown] # ## Compare with target annotation @@ -383,8 +332,8 @@ tmp_dot.remove() feat_observed = data[idx].dropna() - label_template = '{method} (N={n:,d}, q={q:.3f})' - key = label_template.format(method='measured', + label_template = '{method}\n(N={n:,d}, q={q:.3f})' + key = label_template.format(method='observed', n=len(feat_observed), q=float(qvalues.loc[idx, ('None', 'qvalue')]) ) @@ -427,7 +376,7 @@ order=groups_order, dodge=True, hue=args.target, - size=1, + size=2, ax=ax) first_pg = idx.split(";")[0] ax.set_title( @@ -448,7 +397,6 @@ _ = ax.collections[0].set_paths([new_mk]) _ = ax.collections[1].set_paths([new_mk]) - # import matplotlib.lines as mlines label_target_0, label_target_1 = ax.collections[-2].get_label(), ax.collections[-1].get_label() _ = ax.collections[-2].set_label(f'imputed, {label_target_0}') _ = ax.collections[-1].set_label(f'imputed, {label_target_1}') diff --git a/project/config/appl_ald_data/plasma/proteinGroups/comparison.yaml b/project/config/appl_ald_data/plasma/proteinGroups/comparison.yaml index 17c5ebdd2..c2f01d2b8 100644 --- a/project/config/appl_ald_data/plasma/proteinGroups/comparison.yaml +++ b/project/config/appl_ald_data/plasma/proteinGroups/comparison.yaml @@ -1,8 +1,8 @@ folder_experiment: runs/appl_ald_data/plasma/proteinGroups out_folder: diff_analysis # subfolder of experiment folder -fn_rawfile_metadata: 'data/ALD_study/processed/raw_meta.csv' +fn_rawfile_metadata: "data/ALD_study/processed/raw_meta.csv" make_plots: True -covar: +covar: kleiner: age,bmi,gender_num,nas_steatosis_ordinal,abstinent_num inflammation: age,bmi,gender_num,nas_steatosis_ordinal,abstinent_num steatosis: age,bmi,gender_num,abstinent_num,kleiner,nas_inflam @@ -19,9 +19,10 @@ annotaitons_gene_col: PG.Genes baseline: RSN ref_method_score: methods: - - Median - - CF - - DAE - - VAE - - rf - - KNN + - Median + - CF + - DAE + - VAE + - QRILC + - TRKNN + - RF diff --git a/project/config/appl_ald_data/plasma/proteinGroups/config.yaml b/project/config/appl_ald_data/plasma/proteinGroups/config.yaml index af955b8ae..83b6a5ded 100644 --- a/project/config/appl_ald_data/plasma/proteinGroups/config.yaml +++ b/project/config/appl_ald_data/plasma/proteinGroups/config.yaml @@ -12,24 +12,27 @@ models: - VAE - KNN NAGuideR_methods: - - ZERO - - MINIMUM + - BPCA - COLMEDIAN - - ROWMEDIAN + - GSIMP + - IMPSEQ + - IMPSEQROB + - IRM - KNN_IMPUTE - # - SEQKNN # error - - BPCA - - SVDMETHOD - LLS - - MLE - - QRILC + # - MICE-CART # stopped after 24h + # - MICE-NORM # stopped after 24h - MINDET + - MINIMUM - MINPROB - - IRM - # - IMPSEQ # error - - IMPSEQROB - # - MICE-NORM # stopped after 30mins - # - MICE-CART # stopped after 30mins - # - TRKNN # error + - MLE + - MSIMPUTE + - MSIMPUTE_MNAR + - PI + - QRILC - RF - - PI \ No newline at end of file + - ROWMEDIAN + # - SEQKNN # Error in x[od, ismiss, drop = FALSE]: subscript out of bounds + - SVDMETHOD + - TRKNN + - ZERO From 748a1d74573d384a479b2d180693fb276e1a9277 Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 26 Nov 2023 18:23:09 +0100 Subject: [PATCH 58/70] :art: allow custom subselection, add NA if not available - Figure 2: add custom selection of models to aggregate best 5 models of several datasets (custom plotting for paper) - rotate performance label - add NA if model did not run (here: error or not finished within 24h) --- project/01_2_performance_plots.ipynb | 207 +++++++++++++++----- project/01_2_performance_plots.py | 154 ++++++++++++--- project/03_2_best_models_comparison_fig2.py | 18 +- vaep/plotting/__init__.py | 33 +++- 4 files changed, 322 insertions(+), 90 deletions(-) diff --git a/project/01_2_performance_plots.ipynb b/project/01_2_performance_plots.ipynb index 18229bd9e..df3aaacc6 100644 --- a/project/01_2_performance_plots.ipynb +++ b/project/01_2_performance_plots.ipynb @@ -32,6 +32,7 @@ "import random\n", "from pathlib import Path\n", "\n", + "from IPython.display import display\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", @@ -119,6 +120,7 @@ "# Machine parsed metadata from rawfile workflow\n", "fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv'\n", "models: str = 'Median,CF,DAE,VAE' # picked models to compare (comma separated)\n", + "sel_models: str = '' # user defined comparison (comma separated)\n", "# Restrict plotting to top N methods for imputation based on error of validation data, maximum 10\n", "plot_to_n: int = 5" ] @@ -184,7 +186,10 @@ "METRIC = 'MAE'\n", "MIN_FREQ = None\n", "MODELS_PASSED = args.models.split(',')\n", - "MODELS = MODELS_PASSED.copy()" + "MODELS = MODELS_PASSED.copy()\n", + "SEL_MODELS = None\n", + "if args.sel_models:\n", + " SEL_MODELS = args.sel_models.split(',')" ] }, { @@ -243,7 +248,7 @@ "id": "ffc6d140-f48e-4477-84f3-47a196e0a3d8", "metadata": {}, "source": [ - "## Across data completeness" + "## data completeness across entire data" ] }, { @@ -258,7 +263,6 @@ "# load frequency of training features...\n", "# needs to be pickle -> index.name needed\n", "freq_feat = vaep.io.datasplits.load_freq(args.data, file='freq_features.json')\n", - "\n", "freq_feat.head() # training data" ] }, @@ -272,7 +276,15 @@ "outputs": [], "source": [ "prop = freq_feat / len(data.train_X.index.levels[0])\n", - "prop.to_frame()" + "prop.sort_values().to_frame().plot()" + ] + }, + { + "cell_type": "markdown", + "id": "19e5adfb", + "metadata": {}, + "source": [ + "View training data in wide format" ] }, { @@ -288,6 +300,14 @@ "data.train_X" ] }, + { + "cell_type": "markdown", + "id": "21102a1d", + "metadata": {}, + "source": [ + "Number of samples and features:" + ] + }, { "cell_type": "code", "execution_count": null, @@ -301,6 +321,14 @@ "print(f\"N samples: {N_SAMPLES:,d}, M features: {M_FEAT}\")" ] }, + { + "cell_type": "markdown", + "id": "61186a4e", + "metadata": {}, + "source": [ + "Collect outputs in excel file:" + ] + }, { "cell_type": "code", "execution_count": null, @@ -312,7 +340,8 @@ "source": [ "fname = args.folder_experiment / '01_2_performance_summary.xlsx'\n", "dumps[fname.stem] = fname\n", - "writer = pd.ExcelWriter(fname)" + "writer = pd.ExcelWriter(fname)\n", + "print(f\"Saving to: {fname}\")" ] }, { @@ -320,7 +349,7 @@ "id": "bbe028c4-190d-4d50-b8a7-d109817d7b98", "metadata": {}, "source": [ - "# Model specifications\n", + "## Model specifications\n", "- used for bar plot annotations" ] }, @@ -365,19 +394,8 @@ "outputs": [], "source": [ "# index name\n", - "freq_feat.index.name = data.train_X.columns.name" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8088a91f-6aaa-4b9d-b855-332d2bbf5780", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# index name\n", + "freq_feat.index.name = data.train_X.columns.name\n", + "# sample index name\n", "sample_index_name = data.train_X.index.name" ] }, @@ -446,7 +464,7 @@ "lines_to_next_cell": 0 }, "source": [ - "## Select top N for plotting and set colors" + "### Select top N for plotting and set colors" ] }, { @@ -478,18 +496,20 @@ "source": [ "mae_stats_ordered_val = errors_val.abs().describe()[ORDER_MODELS]\n", "mae_stats_ordered_val.to_excel(writer, sheet_name='mae_stats_ordered_val', float_format='%.5f')\n", - "mae_stats_ordered_val" + "mae_stats_ordered_val.T" ] }, { "cell_type": "markdown", "id": "f5b33f93", - "metadata": { - "lines_to_next_cell": 0 - }, + "metadata": {}, "source": [ - "Hack color order, by assing CF, DAE and VAE unique colors no matter their order\n", - "Could be extended to all supported imputation methods" + "Some model have fixed colors, others are assigned randomly\n", + "\n", + "> Note\n", + ">\n", + "> 1. The order of \"new\" models is important for the color assignment.\n", + "> 2. User defined model keys for the same model with two configuration will yield different colors." ] }, { @@ -514,12 +534,9 @@ }, "outputs": [], "source": [ - "# For top_N -> define colors\n", "TOP_N_ORDER = ORDER_MODELS[:args.plot_to_n]\n", - "\n", "TOP_N_COLOR_PALETTE = {model: color for model,\n", " color in zip(TOP_N_ORDER, COLORS_TO_USE)}\n", - "\n", "TOP_N_ORDER" ] }, @@ -678,7 +695,7 @@ }, "outputs": [], "source": [ - "errors_val.describe() # mean of means" + "errors_val.describe()[ORDER_MODELS].T # mean of means" ] }, { @@ -692,7 +709,7 @@ "outputs": [], "source": [ "c_avg_error = 2\n", - "mask = (errors_val[MODELS] >= c_avg_error).any(axis=1)\n", + "mask = (errors_val[TOP_N_ORDER] >= c_avg_error).any(axis=1)\n", "errors_val.loc[mask]" ] }, @@ -715,15 +732,16 @@ "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(8, 3))\n", - "ax, errors_binned = vaep.plotting.errors.plot_errors_binned(\n", + "ax, errors_binned = vaep.plotting.errors.plot_errors_by_median(\n", " pred_val[\n", " [TARGET_COL] + TOP_N_ORDER\n", " ],\n", + " feat_medians=data.train_X.median(),\n", " ax=ax,\n", " palette=TOP_N_COLOR_PALETTE,\n", " metric_name=METRIC,)\n", "ax.set_ylabel(f\"Average error ({METRIC})\")\n", - "fname = args.out_figures / f'2_{group}_errors_binned_by_int_val.pdf'\n", + "fname = args.out_figures / f'2_{group}_errors_binned_by_feat_median_val.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), name=fname)" ] @@ -845,7 +863,7 @@ "lines_to_next_cell": 0 }, "source": [ - "## Intensity distribution as histogram\n", + "### Intensity distribution as histogram\n", "Plot top 4 models predictions for intensities in test data" ] }, @@ -880,8 +898,8 @@ " ax=ax,\n", " alpha=0.5,\n", " )\n", - " _ = [(l.set_rotation(90))\n", - " for l in ax.get_xticklabels()]\n", + " _ = [(l_.set_rotation(90))\n", + " for l_ in ax.get_xticklabels()]\n", " ax.legend()\n", "\n", "axes[0].set_ylabel('Number of observations')\n", @@ -1217,7 +1235,7 @@ " build_text,\n", " axis=1)\n", "except KeyError:\n", - " logger.warning(\"No model PIMMS models in comparsion. Using empty text\")\n", + " logger.warning(\"No PIMMS models in comparsion. Using empty text\")\n", " text = pd.Series('', index=model_configs.columns)\n", "\n", "_to_plot.loc[\"text\"] = text\n", @@ -1235,12 +1253,13 @@ "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(4, 2))\n", - "ax = _to_plot.loc[[feature_names.name]].plot.bar(rot=0,\n", - " ylabel=f\"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)\",\n", - " # title=f'performance on test data (based on {n_in_comparison:,} measurements)',\n", - " color=COLORS_TO_USE,\n", - " ax=ax,\n", - " width=.8)\n", + "ax = _to_plot.loc[[feature_names.name]].plot.bar(\n", + " rot=0,\n", + " ylabel=f\"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)\",\n", + " # title=f'performance on test data (based on {n_in_comparison:,} measurements)',\n", + " color=COLORS_TO_USE,\n", + " ax=ax,\n", + " width=.8)\n", "ax = vaep.plotting.add_height_to_barplot(ax, size=5)\n", "ax = vaep.plotting.add_text_to_barplot(ax, _to_plot.loc[\"text\"], size=5)\n", "ax.set_xticklabels([])\n", @@ -1273,7 +1292,7 @@ "id": "d88c21c7", "metadata": {}, "source": [ - "Plot error by median feature intensity" + "### Plot error by median feature intensity" ] }, { @@ -1306,6 +1325,106 @@ "errors_binned" ] }, + { + "cell_type": "markdown", + "id": "26370a1a", + "metadata": {}, + "source": [ + "### Custom model selection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "712faf9a", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "if SEL_MODELS:\n", + " metrics = vaep.models.Metrics()\n", + " test_metrics = metrics.add_metrics(\n", + " pred_test[['observed', *SEL_MODELS]], key='test data')\n", + " test_metrics = pd.DataFrame(test_metrics)[SEL_MODELS]\n", + " test_metrics\n", + "\n", + " n_in_comparison = int(test_metrics.loc['N'].unique()[0])\n", + " n_in_comparison\n", + "\n", + " _to_plot = test_metrics.loc[METRIC].to_frame().T\n", + " _to_plot.index = [feature_names.name]\n", + " _to_plot\n", + "\n", + " try:\n", + " text = model_configs[[\"latent_dim\", \"hidden_layers\"]].apply(\n", + " build_text,\n", + " axis=1)\n", + " except KeyError:\n", + " logger.warning(\"No PIMMS models in comparsion. Using empty text\")\n", + " text = pd.Series('', index=model_configs.columns)\n", + "\n", + " _to_plot.loc[\"text\"] = text\n", + " _to_plot = _to_plot.fillna('')\n", + " _to_plot\n", + "\n", + " fig, ax = plt.subplots(figsize=(4, 2))\n", + " ax = _to_plot.loc[[feature_names.name]].plot.bar(\n", + " rot=0,\n", + " ylabel=f\"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)\",\n", + " # title=f'performance on test data (based on {n_in_comparison:,} measurements)',\n", + " color=COLORS_TO_USE,\n", + " ax=ax,\n", + " width=.8)\n", + " ax = vaep.plotting.add_height_to_barplot(ax, size=5)\n", + " ax = vaep.plotting.add_text_to_barplot(ax, _to_plot.loc[\"text\"], size=5)\n", + " ax.set_xticklabels([])\n", + " fname = args.out_figures / f'2_{group}_performance_test_sel.pdf'\n", + " figures[fname.stem] = fname\n", + " vaep.savefig(fig, name=fname)\n", + "\n", + " dumps[fname.stem] = fname.with_suffix('.csv')\n", + " _to_plot_long = _to_plot.T\n", + " _to_plot_long = _to_plot_long.rename(\n", + " {feature_names.name: 'metric_value'}, axis=1)\n", + " _to_plot_long['data level'] = feature_names.name\n", + " _to_plot_long = _to_plot_long.set_index('data level', append=True)\n", + " _to_plot_long.to_csv(fname.with_suffix('.csv'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2a578570", + "metadata": {}, + "outputs": [], + "source": [ + "# custom selection\n", + "if SEL_MODELS:\n", + " vaep.plotting.make_large_descriptors(6)\n", + " fig, ax = plt.subplots(figsize=(8, 2))\n", + "\n", + " ax, errors_binned = vaep.plotting.errors.plot_errors_by_median(\n", + " pred=pred_test[\n", + " [TARGET_COL] + SEL_MODELS\n", + " ],\n", + " feat_medians=data.train_X.median(),\n", + " ax=ax,\n", + " metric_name=METRIC,\n", + " palette=COLORS_TO_USE\n", + " )\n", + " ax.set_ylim(0, 1.5)\n", + " # for text in ax.legend().get_texts():\n", + " # text.set_fontsize(6)\n", + " fname = args.out_figures / f'2_{group}_test_errors_binned_by_feat_medians_sel.pdf'\n", + " figures[fname.stem] = fname\n", + " vaep.savefig(ax.get_figure(), name=fname)\n", + " # vaep.plotting.make_large_descriptors(6)\n", + " dumps[fname.stem] = fname.with_suffix('.csv')\n", + " errors_binned.to_csv(fname.with_suffix('.csv'))\n", + " display(errors_binned)" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/project/01_2_performance_plots.py b/project/01_2_performance_plots.py index 53221562e..fa8954e20 100644 --- a/project/01_2_performance_plots.py +++ b/project/01_2_performance_plots.py @@ -32,6 +32,7 @@ import random from pathlib import Path +from IPython.display import display import matplotlib.pyplot as plt import numpy as np import pandas as pd @@ -94,6 +95,7 @@ def build_text(s): # Machine parsed metadata from rawfile workflow fn_rawfile_metadata: str = 'data/dev_datasets/HeLa_6070/files_selected_metadata_N50.csv' models: str = 'Median,CF,DAE,VAE' # picked models to compare (comma separated) +sel_models: str = '' # user defined comparison (comma separated) # Restrict plotting to top N methods for imputation based on error of validation data, maximum 10 plot_to_n: int = 5 @@ -119,6 +121,9 @@ def build_text(s): MIN_FREQ = None MODELS_PASSED = args.models.split(',') MODELS = MODELS_PASSED.copy() +SEL_MODELS = None +if args.sel_models: + SEL_MODELS = args.sel_models.split(',') # %% @@ -146,34 +151,43 @@ def build_text(s): vaep.savefig(fig, name=fname) # %% [markdown] -# ## Across data completeness +# ## data completeness across entire data # %% # load frequency of training features... # needs to be pickle -> index.name needed freq_feat = vaep.io.datasplits.load_freq(args.data, file='freq_features.json') - freq_feat.head() # training data # %% prop = freq_feat / len(data.train_X.index.levels[0]) -prop.to_frame() +prop.sort_values().to_frame().plot() + +# %% [markdown] +# View training data in wide format # %% data.to_wide_format() data.train_X +# %% [markdown] +# Number of samples and features: + # %% N_SAMPLES, M_FEAT = data.train_X.shape print(f"N samples: {N_SAMPLES:,d}, M features: {M_FEAT}") +# %% [markdown] +# Collect outputs in excel file: + # %% fname = args.folder_experiment / '01_2_performance_summary.xlsx' dumps[fname.stem] = fname writer = pd.ExcelWriter(fname) +print(f"Saving to: {fname}") # %% [markdown] -# # Model specifications +# ## Model specifications # - used for bar plot annotations # %% @@ -196,9 +210,7 @@ def build_text(s): # %% # index name freq_feat.index.name = data.train_X.columns.name - -# %% -# index name +# sample index name sample_index_name = data.train_X.index.name # %% [markdown] @@ -228,7 +240,7 @@ def build_text(s): errors_val # over all samples and all features # %% [markdown] -# ## Select top N for plotting and set colors +# ### Select top N for plotting and set colors # %% ORDER_MODELS = (errors_val .abs() @@ -241,22 +253,24 @@ def build_text(s): # %% mae_stats_ordered_val = errors_val.abs().describe()[ORDER_MODELS] mae_stats_ordered_val.to_excel(writer, sheet_name='mae_stats_ordered_val', float_format='%.5f') -mae_stats_ordered_val +mae_stats_ordered_val.T # %% [markdown] -# Hack color order, by assing CF, DAE and VAE unique colors no matter their order -# Could be extended to all supported imputation methods +# Some model have fixed colors, others are assigned randomly +# +# > Note +# > +# > 1. The order of "new" models is important for the color assignment. +# > 2. User defined model keys for the same model with two configuration will yield different colors. + # %% COLORS_TO_USE = vaep.plotting.defaults.assign_colors(list(k.upper() for k in ORDER_MODELS)) sns.color_palette(COLORS_TO_USE) # %% -# For top_N -> define colors TOP_N_ORDER = ORDER_MODELS[:args.plot_to_n] - TOP_N_COLOR_PALETTE = {model: color for model, color in zip(TOP_N_ORDER, COLORS_TO_USE)} - TOP_N_ORDER # %% [markdown] @@ -336,11 +350,11 @@ def build_text(s): # Some interpolated features are missing # %% -errors_val.describe() # mean of means +errors_val.describe()[ORDER_MODELS].T # mean of means # %% c_avg_error = 2 -mask = (errors_val[MODELS] >= c_avg_error).any(axis=1) +mask = (errors_val[TOP_N_ORDER] >= c_avg_error).any(axis=1) errors_val.loc[mask] @@ -350,15 +364,16 @@ def build_text(s): # %% fig, ax = plt.subplots(figsize=(8, 3)) -ax, errors_binned = vaep.plotting.errors.plot_errors_binned( +ax, errors_binned = vaep.plotting.errors.plot_errors_by_median( pred_val[ [TARGET_COL] + TOP_N_ORDER ], + feat_medians=data.train_X.median(), ax=ax, palette=TOP_N_COLOR_PALETTE, metric_name=METRIC,) ax.set_ylabel(f"Average error ({METRIC})") -fname = args.out_figures / f'2_{group}_errors_binned_by_int_val.pdf' +fname = args.out_figures / f'2_{group}_errors_binned_by_feat_median_val.pdf' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) @@ -409,7 +424,7 @@ def build_text(s): writer.close() # %% [markdown] -# ## Intensity distribution as histogram +# ### Intensity distribution as histogram # Plot top 4 models predictions for intensities in test data # %% min_max = vaep.plotting.data.min_max(pred_test[TARGET_COL]) @@ -434,8 +449,8 @@ def build_text(s): ax=ax, alpha=0.5, ) - _ = [(l.set_rotation(90)) - for l in ax.get_xticklabels()] + _ = [(l_.set_rotation(90)) + for l_ in ax.get_xticklabels()] ax.legend() axes[0].set_ylabel('Number of observations') @@ -608,7 +623,7 @@ def highlight_min(s, color, tolerence=0.00001): build_text, axis=1) except KeyError: - logger.warning("No model PIMMS models in comparsion. Using empty text") + logger.warning("No PIMMS models in comparsion. Using empty text") text = pd.Series('', index=model_configs.columns) _to_plot.loc["text"] = text @@ -618,12 +633,13 @@ def highlight_min(s, color, tolerence=0.00001): # %% fig, ax = plt.subplots(figsize=(4, 2)) -ax = _to_plot.loc[[feature_names.name]].plot.bar(rot=0, - ylabel=f"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)", - # title=f'performance on test data (based on {n_in_comparison:,} measurements)', - color=COLORS_TO_USE, - ax=ax, - width=.8) +ax = _to_plot.loc[[feature_names.name]].plot.bar( + rot=0, + ylabel=f"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)", + # title=f'performance on test data (based on {n_in_comparison:,} measurements)', + color=COLORS_TO_USE, + ax=ax, + width=.8) ax = vaep.plotting.add_height_to_barplot(ax, size=5) ax = vaep.plotting.add_text_to_barplot(ax, _to_plot.loc["text"], size=5) ax.set_xticklabels([]) @@ -642,7 +658,7 @@ def highlight_min(s, color, tolerence=0.00001): # %% [markdown] -# Plot error by median feature intensity +# ### Plot error by median feature intensity # %% fig, ax = plt.subplots(figsize=(8, 2)) @@ -665,6 +681,86 @@ def highlight_min(s, color, tolerence=0.00001): errors_binned.to_csv(fname.with_suffix('.csv')) errors_binned +# %% [markdown] +# ### Custom model selection + +# %% +if SEL_MODELS: + metrics = vaep.models.Metrics() + test_metrics = metrics.add_metrics( + pred_test[['observed', *SEL_MODELS]], key='test data') + test_metrics = pd.DataFrame(test_metrics)[SEL_MODELS] + test_metrics + + n_in_comparison = int(test_metrics.loc['N'].unique()[0]) + n_in_comparison + + _to_plot = test_metrics.loc[METRIC].to_frame().T + _to_plot.index = [feature_names.name] + _to_plot + + try: + text = model_configs[["latent_dim", "hidden_layers"]].apply( + build_text, + axis=1) + except KeyError: + logger.warning("No PIMMS models in comparsion. Using empty text") + text = pd.Series('', index=model_configs.columns) + + _to_plot.loc["text"] = text + _to_plot = _to_plot.fillna('') + _to_plot + + fig, ax = plt.subplots(figsize=(4, 2)) + ax = _to_plot.loc[[feature_names.name]].plot.bar( + rot=0, + ylabel=f"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)", + # title=f'performance on test data (based on {n_in_comparison:,} measurements)', + color=COLORS_TO_USE, + ax=ax, + width=.8) + ax = vaep.plotting.add_height_to_barplot(ax, size=5) + ax = vaep.plotting.add_text_to_barplot(ax, _to_plot.loc["text"], size=5) + ax.set_xticklabels([]) + fname = args.out_figures / f'2_{group}_performance_test_sel.pdf' + figures[fname.stem] = fname + vaep.savefig(fig, name=fname) + + dumps[fname.stem] = fname.with_suffix('.csv') + _to_plot_long = _to_plot.T + _to_plot_long = _to_plot_long.rename( + {feature_names.name: 'metric_value'}, axis=1) + _to_plot_long['data level'] = feature_names.name + _to_plot_long = _to_plot_long.set_index('data level', append=True) + _to_plot_long.to_csv(fname.with_suffix('.csv')) + + +# %% +# custom selection +if SEL_MODELS: + vaep.plotting.make_large_descriptors(6) + fig, ax = plt.subplots(figsize=(8, 2)) + + ax, errors_binned = vaep.plotting.errors.plot_errors_by_median( + pred=pred_test[ + [TARGET_COL] + SEL_MODELS + ], + feat_medians=data.train_X.median(), + ax=ax, + metric_name=METRIC, + palette=COLORS_TO_USE + ) + ax.set_ylim(0, 1.5) + # for text in ax.legend().get_texts(): + # text.set_fontsize(6) + fname = args.out_figures / f'2_{group}_test_errors_binned_by_feat_medians_sel.pdf' + figures[fname.stem] = fname + vaep.savefig(ax.get_figure(), name=fname) + # vaep.plotting.make_large_descriptors(6) + dumps[fname.stem] = fname.with_suffix('.csv') + errors_binned.to_csv(fname.with_suffix('.csv')) + display(errors_binned) + # %% (errors_binned .set_index( diff --git a/project/03_2_best_models_comparison_fig2.py b/project/03_2_best_models_comparison_fig2.py index 55c5a0d5c..39921344e 100644 --- a/project/03_2_best_models_comparison_fig2.py +++ b/project/03_2_best_models_comparison_fig2.py @@ -36,18 +36,18 @@ FOLDER = Path('runs/mnar_mcar/') SIZE = 'l' files_in = { - 'protein groups': FOLDER / 'pg_l_25MNAR/figures/2_1_performance_test.csv', - 'peptides': FOLDER / 'pep_l_25MNAR/figures/2_1_performance_test.csv', - 'precursors': FOLDER / 'evi_l_25MNAR/figures/2_1_performance_test.csv' + 'protein groups': FOLDER / 'pg_l_25MNAR/figures/2_1_performance_test_sel.csv', + 'peptides': FOLDER / 'pep_l_25MNAR/figures/2_1_performance_test_sel.csv', + 'precursors': FOLDER / 'evi_l_25MNAR/figures/2_1_performance_test_sel.csv' } # %% FOLDER = Path('runs/mnar_mcar/') SIZE = 'm' files_in = { - 'protein groups': FOLDER / 'pg_m_25MNAR/figures/2_1_performance_test.csv', - 'peptides': FOLDER / 'pep_m_25MNAR/figures/2_1_performance_test.csv', - 'precursors': FOLDER / 'evi_m_25MNAR/figures/2_1_performance_test.csv' + 'protein groups': FOLDER / 'pg_m_25MNAR/figures/2_1_performance_test_sel.csv', + 'peptides': FOLDER / 'pep_m_25MNAR/figures/2_1_performance_test_sel.csv', + 'precursors': FOLDER / 'evi_m_25MNAR/figures/2_1_performance_test_sel.csv' } # %% @@ -104,7 +104,9 @@ fontsize=7 )) -ax = vaep.plotting.add_height_to_barplot(ax, size=5) + +ax = vaep.plotting.add_height_to_barplot(ax, size=6, rotated=True) +ax.set_ylim((0, 0.75)) ax.legend(fontsize=5, loc='lower right') text = ( df['text'] @@ -113,7 +115,7 @@ .stack().loc[pd.IndexSlice[ORDER_MODELS, ORDER_DATA]] ) -ax = vaep.plotting.add_text_to_barplot(ax, text, size=5) +ax = vaep.plotting.add_text_to_barplot(ax, text, size=6) fig = ax.get_figure() fig.tight_layout() vaep.savefig(fig, fname) diff --git a/vaep/plotting/__init__.py b/vaep/plotting/__init__.py index a1fab486a..38e39c8d4 100644 --- a/vaep/plotting/__init__.py +++ b/vaep/plotting/__init__.py @@ -1,5 +1,6 @@ from __future__ import annotations +from functools import partial import numpy as np import pandas as pd import matplotlib @@ -155,30 +156,44 @@ def add_prop_as_second_yaxis(ax: matplotlib.axes.Axes, n_samples: int, return ax2 -def add_height_to_barplot(ax, size=5): +def add_height_to_barplot(ax, size=5, rotated=False): + ax.annotate = partial(ax.annotate, text='NA', + xytext=(0, int(size / 2)), + ha='center', + size=size, + textcoords='offset points') + ax.annotate = partial(ax.annotate, + rotation=0, + va='center') + if rotated: + ax.annotate = partial(ax.annotate, + xytext=(1, int(size / 3)), + rotation=90, + va='bottom') for bar in ax.patches: if not bar.get_height(): + xy = (bar.get_x() + bar.get_width() / 2, + 0.0) + ax.annotate(text='NA', + xy=xy, + ) continue ax.annotate(text=format(bar.get_height(), '.2f'), xy=(bar.get_x() + bar.get_width() / 2, bar.get_height()), - xytext=(0, int(size / 2)), - ha='center', - va='center', - size=size, - textcoords='offset points') + ) return ax def add_text_to_barplot(ax, text, size=5): - for bar, text in zip(ax.patches, text): + for bar, text_ in zip(ax.patches, text): logger.debug(f"{bar = }, f{text = }, {bar.get_height() = }") if not bar.get_height(): continue - ax.annotate(text=text, + ax.annotate(text=text_, xy=(bar.get_x() + bar.get_width() / 2, bar.get_height()), - xytext=(0, -5), + xytext=(1, -5), rotation=90, ha='center', va='top', From 1f2d6825fba58564a88f1903ce7a4dd670639a40 Mon Sep 17 00:00:00 2001 From: Henry Webel Date: Sun, 26 Nov 2023 19:36:27 +0100 Subject: [PATCH 59/70] :bug: sync and specify selected - for large pep and evi, the top five are already the correct set --- .../03_2_best_models_comparison_fig2.ipynb | 22 ++++++++++++++----- project/03_2_best_models_comparison_fig2.py | 6 +++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/project/03_2_best_models_comparison_fig2.ipynb b/project/03_2_best_models_comparison_fig2.ipynb index 199587add..6370691f4 100644 --- a/project/03_2_best_models_comparison_fig2.ipynb +++ b/project/03_2_best_models_comparison_fig2.ipynb @@ -37,7 +37,7 @@ "FOLDER = Path('runs/mnar_mcar/')\n", "SIZE = 'l'\n", "files_in = {\n", - " 'protein groups': FOLDER / 'pg_l_25MNAR/figures/2_1_performance_test.csv',\n", + " 'protein groups': FOLDER / 'pg_l_25MNAR/figures/2_1_performance_test_sel.csv',\n", " 'peptides': FOLDER / 'pep_l_25MNAR/figures/2_1_performance_test.csv',\n", " 'precursors': FOLDER / 'evi_l_25MNAR/figures/2_1_performance_test.csv'\n", "}" @@ -53,9 +53,9 @@ "FOLDER = Path('runs/mnar_mcar/')\n", "SIZE = 'm'\n", "files_in = {\n", - " 'protein groups': FOLDER / 'pg_m_25MNAR/figures/2_1_performance_test.csv',\n", - " 'peptides': FOLDER / 'pep_m_25MNAR/figures/2_1_performance_test.csv',\n", - " 'precursors': FOLDER / 'evi_m_25MNAR/figures/2_1_performance_test.csv'\n", + " 'protein groups': FOLDER / 'pg_m_25MNAR/figures/2_1_performance_test_sel.csv',\n", + " 'peptides': FOLDER / 'pep_m_25MNAR/figures/2_1_performance_test_sel.csv',\n", + " 'precursors': FOLDER / 'evi_m_25MNAR/figures/2_1_performance_test_sel.csv'\n", "}" ] }, @@ -154,7 +154,9 @@ " fontsize=7\n", " ))\n", "\n", - "ax = vaep.plotting.add_height_to_barplot(ax, size=5)\n", + "\n", + "ax = vaep.plotting.add_height_to_barplot(ax, size=6, rotated=True)\n", + "ax.set_ylim((0, 0.75))\n", "ax.legend(fontsize=5, loc='lower right')\n", "text = (\n", " df['text']\n", @@ -163,7 +165,7 @@ " .stack().loc[pd.IndexSlice[ORDER_MODELS, ORDER_DATA]]\n", "\n", ")\n", - "ax = vaep.plotting.add_text_to_barplot(ax, text, size=5)\n", + "ax = vaep.plotting.add_text_to_barplot(ax, text, size=6)\n", "fig = ax.get_figure()\n", "fig.tight_layout()\n", "vaep.savefig(fig, fname)" @@ -236,6 +238,14 @@ "perf.to_excel(fname)\n", "fname.as_posix()" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d97a66a0", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/project/03_2_best_models_comparison_fig2.py b/project/03_2_best_models_comparison_fig2.py index 39921344e..d5b69eae1 100644 --- a/project/03_2_best_models_comparison_fig2.py +++ b/project/03_2_best_models_comparison_fig2.py @@ -37,8 +37,8 @@ SIZE = 'l' files_in = { 'protein groups': FOLDER / 'pg_l_25MNAR/figures/2_1_performance_test_sel.csv', - 'peptides': FOLDER / 'pep_l_25MNAR/figures/2_1_performance_test_sel.csv', - 'precursors': FOLDER / 'evi_l_25MNAR/figures/2_1_performance_test_sel.csv' + 'peptides': FOLDER / 'pep_l_25MNAR/figures/2_1_performance_test.csv', + 'precursors': FOLDER / 'evi_l_25MNAR/figures/2_1_performance_test.csv' } # %% @@ -155,3 +155,5 @@ fname = FOLDER / f'performance_summary_{SIZE}.xlsx' perf.to_excel(fname) fname.as_posix() + +# %% From e206483c0c1e886efa3fce0a78f6102c8e2c30fb Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 27 Nov 2023 12:04:48 +0100 Subject: [PATCH 60/70] :bug::sparkles: Pick colors for selected - for subselected models the colors were not reselected --- project/01_2_performance_plots.ipynb | 6 ++++-- project/01_2_performance_plots.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/project/01_2_performance_plots.ipynb b/project/01_2_performance_plots.ipynb index df3aaacc6..d22c2c200 100644 --- a/project/01_2_performance_plots.ipynb +++ b/project/01_2_performance_plots.ipynb @@ -1373,7 +1373,8 @@ " rot=0,\n", " ylabel=f\"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)\",\n", " # title=f'performance on test data (based on {n_in_comparison:,} measurements)',\n", - " color=COLORS_TO_USE,\n", + " color=vaep.plotting.defaults.assign_colors(\n", + " list(k.upper() for k in SEL_MODELS)),\n", " ax=ax,\n", " width=.8)\n", " ax = vaep.plotting.add_height_to_barplot(ax, size=5)\n", @@ -1411,7 +1412,8 @@ " feat_medians=data.train_X.median(),\n", " ax=ax,\n", " metric_name=METRIC,\n", - " palette=COLORS_TO_USE\n", + " palette=vaep.plotting.defaults.assign_colors(\n", + " list(k.upper() for k in SEL_MODELS))\n", " )\n", " ax.set_ylim(0, 1.5)\n", " # for text in ax.legend().get_texts():\n", diff --git a/project/01_2_performance_plots.py b/project/01_2_performance_plots.py index fa8954e20..7150f8e33 100644 --- a/project/01_2_performance_plots.py +++ b/project/01_2_performance_plots.py @@ -716,7 +716,8 @@ def highlight_min(s, color, tolerence=0.00001): rot=0, ylabel=f"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)", # title=f'performance on test data (based on {n_in_comparison:,} measurements)', - color=COLORS_TO_USE, + color=vaep.plotting.defaults.assign_colors( + list(k.upper() for k in SEL_MODELS)), ax=ax, width=.8) ax = vaep.plotting.add_height_to_barplot(ax, size=5) @@ -748,7 +749,8 @@ def highlight_min(s, color, tolerence=0.00001): feat_medians=data.train_X.median(), ax=ax, metric_name=METRIC, - palette=COLORS_TO_USE + palette=vaep.plotting.defaults.assign_colors( + list(k.upper() for k in SEL_MODELS)) ) ax.set_ylim(0, 1.5) # for text in ax.legend().get_texts(): From e62f80b5a2a81798556eb416fcb22763b77360cf Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 27 Nov 2023 12:07:14 +0100 Subject: [PATCH 61/70] :art: switch colors and show model tag for color - based on seaborn example of _ColorPalette --- project/01_2_performance_plots.ipynb | 2 +- project/01_2_performance_plots.py | 2 +- vaep/plotting/defaults.py | 30 +++++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/project/01_2_performance_plots.ipynb b/project/01_2_performance_plots.ipynb index d22c2c200..0625bfb37 100644 --- a/project/01_2_performance_plots.ipynb +++ b/project/01_2_performance_plots.ipynb @@ -522,7 +522,7 @@ "outputs": [], "source": [ "COLORS_TO_USE = vaep.plotting.defaults.assign_colors(list(k.upper() for k in ORDER_MODELS))\n", - "sns.color_palette(COLORS_TO_USE)" + "vaep.plotting.defaults.ModelColorVisualizer(ORDER_MODELS, COLORS_TO_USE)" ] }, { diff --git a/project/01_2_performance_plots.py b/project/01_2_performance_plots.py index 7150f8e33..71cfab04a 100644 --- a/project/01_2_performance_plots.py +++ b/project/01_2_performance_plots.py @@ -265,7 +265,7 @@ def build_text(s): # %% COLORS_TO_USE = vaep.plotting.defaults.assign_colors(list(k.upper() for k in ORDER_MODELS)) -sns.color_palette(COLORS_TO_USE) +vaep.plotting.defaults.ModelColorVisualizer(ORDER_MODELS, COLORS_TO_USE) # %% TOP_N_ORDER = ORDER_MODELS[:args.plot_to_n] diff --git a/vaep/plotting/defaults.py b/vaep/plotting/defaults.py index d6e2b5b81..f4a470abe 100644 --- a/vaep/plotting/defaults.py +++ b/vaep/plotting/defaults.py @@ -1,4 +1,5 @@ import logging +import matplotlib as mpl import seaborn as sns logger = logging.getLogger(__name__) @@ -22,10 +23,11 @@ # other_colors = sns.color_palette()[8:] other_colors = sns.color_palette("husl", 20) color_model_mapping['IMPSEQ'] = other_colors[0] +color_model_mapping['QRILC'] = other_colors[1] color_model_mapping['IMPSEQROB'] = other_colors[1] color_model_mapping['MICE-NORM'] = other_colors[2] color_model_mapping['SEQKNN'] = other_colors[3] -color_model_mapping['QRILC'] = other_colors[4] +color_model_mapping['IMPSEQROB'] = other_colors[4] color_model_mapping['GSIMP'] = other_colors[5] color_model_mapping['MSIMPUTE'] = other_colors[6] color_model_mapping['MSIMPUTE_MNAR'] = other_colors[7] @@ -49,6 +51,32 @@ def assign_colors(models): return ret_colors +class ModelColorVisualizer: + + def __init__(self, models, palette): + self.models = models + self.palette = map(mpl.colors.colorConverter.to_rgb, palette) + + def as_hex(self): + """Return a color palette with hex codes instead of RGB values.""" + hex = [mpl.colors.rgb2hex(rgb) for rgb in self.palette] + return hex + + def _repr_html_(self): + """Rich display of the color palette in an HTML frontend.""" + s = 55 + n = len(self.models) + html = f'' + for i, (m, c) in enumerate(zip(self.models, self.as_hex())): + html += ( + f'' + ) + html += f'{m}' + html += '' + return html + + labels_dict = {"NA not interpolated valid_collab collab MSE": 'MSE', 'batch_size': 'bs', 'n_hidden_layers': "No. of hidden layers", From db2469a55e67b64ef4c9132506ef63dedb8e62b6 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 27 Nov 2023 12:57:12 +0100 Subject: [PATCH 62/70] :art: center swarmplot labels --- project/10_4_ald_compare_single_pg.ipynb | 35 +++++++++++++++--------- project/10_4_ald_compare_single_pg.py | 35 +++++++++++++++--------- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/project/10_4_ald_compare_single_pg.ipynb b/project/10_4_ald_compare_single_pg.ipynb index 0b60a92c0..3de5bb57b 100644 --- a/project/10_4_ald_compare_single_pg.ipynb +++ b/project/10_4_ald_compare_single_pg.ipynb @@ -625,11 +625,20 @@ " tmp_dot.remove()\n", "\n", " feat_observed = data[idx].dropna()\n", - " label_template = '{method}\\n(N={n:,d}, q={q:.3f})'\n", - " key = label_template.format(method='observed',\n", - " n=len(feat_observed),\n", - " q=float(qvalues.loc[idx, ('None', 'qvalue')])\n", - " )\n", + "\n", + " def get_centered_label(method, n, q):\n", + " model_str = f'{method}'\n", + " stats_str = f'(N={n:,d}, q={q:.3f})'\n", + " if len(model_str) > len(stats_str):\n", + " stats_str = f\"{stats_str:<{len(model_str)}}\"\n", + " else:\n", + " model_str = f\"{model_str:<{len(stats_str)}}\"\n", + " return f'{model_str}\\n{stats_str}'\n", + "\n", + " key = get_centered_label(method='observed',\n", + " n=len(feat_observed),\n", + " q=float(qvalues.loc[idx, ('None', 'qvalue')])\n", + " )\n", " to_plot = {key: feat_observed}\n", " for method in model_keys:\n", " try:\n", @@ -637,15 +646,15 @@ " idx], method].dropna().droplevel(-1)\n", " if len(pred) == 0:\n", " # in case no values was imputed -> qvalue is as based on measured\n", - " key = label_template.format(method=method,\n", - " n=len(pred),\n", - " q=float(qvalues.loc[idx, ('None', 'qvalue')]\n", - " ))\n", + " key = get_centered_label(method=method,\n", + " n=len(pred),\n", + " q=float(qvalues.loc[idx, ('None', 'qvalue')]\n", + " ))\n", " elif qvalues.loc[idx, (method, 'qvalue')].notna().all():\n", - " key = label_template.format(method=method,\n", - " n=len(pred),\n", - " q=float(qvalues.loc[idx, (method, 'qvalue')]\n", - " ))\n", + " key = get_centered_label(method=method,\n", + " n=len(pred),\n", + " q=float(qvalues.loc[idx, (method, 'qvalue')]\n", + " ))\n", " elif qvalues.loc[idx, (method, 'qvalue')].isna().all():\n", " logger.info(f\"NA qvalues for {idx}: {method}\")\n", " continue\n", diff --git a/project/10_4_ald_compare_single_pg.py b/project/10_4_ald_compare_single_pg.py index 9e50574b9..96ba6f7c6 100644 --- a/project/10_4_ald_compare_single_pg.py +++ b/project/10_4_ald_compare_single_pg.py @@ -332,11 +332,20 @@ tmp_dot.remove() feat_observed = data[idx].dropna() - label_template = '{method}\n(N={n:,d}, q={q:.3f})' - key = label_template.format(method='observed', - n=len(feat_observed), - q=float(qvalues.loc[idx, ('None', 'qvalue')]) - ) + + def get_centered_label(method, n, q): + model_str = f'{method}' + stats_str = f'(N={n:,d}, q={q:.3f})' + if len(model_str) > len(stats_str): + stats_str = f"{stats_str:<{len(model_str)}}" + else: + model_str = f"{model_str:<{len(stats_str)}}" + return f'{model_str}\n{stats_str}' + + key = get_centered_label(method='observed', + n=len(feat_observed), + q=float(qvalues.loc[idx, ('None', 'qvalue')]) + ) to_plot = {key: feat_observed} for method in model_keys: try: @@ -344,15 +353,15 @@ idx], method].dropna().droplevel(-1) if len(pred) == 0: # in case no values was imputed -> qvalue is as based on measured - key = label_template.format(method=method, - n=len(pred), - q=float(qvalues.loc[idx, ('None', 'qvalue')] - )) + key = get_centered_label(method=method, + n=len(pred), + q=float(qvalues.loc[idx, ('None', 'qvalue')] + )) elif qvalues.loc[idx, (method, 'qvalue')].notna().all(): - key = label_template.format(method=method, - n=len(pred), - q=float(qvalues.loc[idx, (method, 'qvalue')] - )) + key = get_centered_label(method=method, + n=len(pred), + q=float(qvalues.loc[idx, (method, 'qvalue')] + )) elif qvalues.loc[idx, (method, 'qvalue')].isna().all(): logger.info(f"NA qvalues for {idx}: {method}") continue From 49ee8e5109ae3fd6de46e3da9e648e01768c0e1d Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 28 Nov 2023 14:39:03 +0100 Subject: [PATCH 63/70] :art: rotate other direction, use space better improve readability --- project/01_2_performance_plots.ipynb | 10 ++++++---- project/01_2_performance_plots.py | 10 ++++++---- vaep/plotting/errors.py | 8 ++++---- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/project/01_2_performance_plots.ipynb b/project/01_2_performance_plots.ipynb index 0625bfb37..78db92131 100644 --- a/project/01_2_performance_plots.ipynb +++ b/project/01_2_performance_plots.ipynb @@ -1304,6 +1304,7 @@ }, "outputs": [], "source": [ + "vaep.plotting.make_large_descriptors(7)\n", "fig, ax = plt.subplots(figsize=(8, 2))\n", "\n", "ax, errors_binned = vaep.plotting.errors.plot_errors_by_median(\n", @@ -1315,7 +1316,7 @@ " metric_name=METRIC,\n", " palette=COLORS_TO_USE\n", ")\n", - "\n", + "vaep.plotting.make_large_descriptors(6)\n", "fname = args.out_figures / f'2_{group}_test_errors_binned_by_feat_medians.pdf'\n", "figures[fname.stem] = fname\n", "vaep.savefig(ax.get_figure(), name=fname)\n", @@ -1402,7 +1403,7 @@ "source": [ "# custom selection\n", "if SEL_MODELS:\n", - " vaep.plotting.make_large_descriptors(6)\n", + " vaep.plotting.make_large_descriptors(7)\n", " fig, ax = plt.subplots(figsize=(8, 2))\n", "\n", " ax, errors_binned = vaep.plotting.errors.plot_errors_by_median(\n", @@ -1415,15 +1416,16 @@ " palette=vaep.plotting.defaults.assign_colors(\n", " list(k.upper() for k in SEL_MODELS))\n", " )\n", - " ax.set_ylim(0, 1.5)\n", + " # ax.set_ylim(0, 1.5)\n", " # for text in ax.legend().get_texts():\n", " # text.set_fontsize(6)\n", " fname = args.out_figures / f'2_{group}_test_errors_binned_by_feat_medians_sel.pdf'\n", " figures[fname.stem] = fname\n", " vaep.savefig(ax.get_figure(), name=fname)\n", - " # vaep.plotting.make_large_descriptors(6)\n", " dumps[fname.stem] = fname.with_suffix('.csv')\n", " errors_binned.to_csv(fname.with_suffix('.csv'))\n", + " vaep.plotting.make_large_descriptors(6)\n", + " # ax.xaxis.set_tick_params(rotation=0) # horizontal\n", " display(errors_binned)" ] }, diff --git a/project/01_2_performance_plots.py b/project/01_2_performance_plots.py index 71cfab04a..0d1526a09 100644 --- a/project/01_2_performance_plots.py +++ b/project/01_2_performance_plots.py @@ -661,6 +661,7 @@ def highlight_min(s, color, tolerence=0.00001): # ### Plot error by median feature intensity # %% +vaep.plotting.make_large_descriptors(7) fig, ax = plt.subplots(figsize=(8, 2)) ax, errors_binned = vaep.plotting.errors.plot_errors_by_median( @@ -672,7 +673,7 @@ def highlight_min(s, color, tolerence=0.00001): metric_name=METRIC, palette=COLORS_TO_USE ) - +vaep.plotting.make_large_descriptors(6) fname = args.out_figures / f'2_{group}_test_errors_binned_by_feat_medians.pdf' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) @@ -739,7 +740,7 @@ def highlight_min(s, color, tolerence=0.00001): # %% # custom selection if SEL_MODELS: - vaep.plotting.make_large_descriptors(6) + vaep.plotting.make_large_descriptors(7) fig, ax = plt.subplots(figsize=(8, 2)) ax, errors_binned = vaep.plotting.errors.plot_errors_by_median( @@ -752,15 +753,16 @@ def highlight_min(s, color, tolerence=0.00001): palette=vaep.plotting.defaults.assign_colors( list(k.upper() for k in SEL_MODELS)) ) - ax.set_ylim(0, 1.5) + # ax.set_ylim(0, 1.5) # for text in ax.legend().get_texts(): # text.set_fontsize(6) fname = args.out_figures / f'2_{group}_test_errors_binned_by_feat_medians_sel.pdf' figures[fname.stem] = fname vaep.savefig(ax.get_figure(), name=fname) - # vaep.plotting.make_large_descriptors(6) dumps[fname.stem] = fname.with_suffix('.csv') errors_binned.to_csv(fname.with_suffix('.csv')) + vaep.plotting.make_large_descriptors(6) + # ax.xaxis.set_tick_params(rotation=0) # horizontal display(errors_binned) # %% diff --git a/vaep/plotting/errors.py b/vaep/plotting/errors.py index 30d53cb0f..7d6dd790f 100644 --- a/vaep/plotting/errors.py +++ b/vaep/plotting/errors.py @@ -24,7 +24,7 @@ def plot_errors_binned(pred: pd.DataFrame, target_col='observed', len_max_bin = len(str(int(errors_binned['bin'].max()))) n_obs = (errors_binned[meta_cols] .apply( - lambda x: f"{x.bin:0{len_max_bin}} (N={x.n_obs:,d})", axis=1 + lambda x: f"{x.bin:0{len_max_bin}}\n(N={x.n_obs:,d})", axis=1 ) .rename('intensity bin') .astype('category') @@ -43,7 +43,7 @@ def plot_errors_binned(pred: pd.DataFrame, target_col='observed', x='intensity bin', y=metric_name, hue='model', palette=palette, errwidth=errwidth,) - ax.xaxis.set_tick_params(rotation=-90) + ax.xaxis.set_tick_params(rotation=90) return ax, errors_binned @@ -83,7 +83,7 @@ def plot_errors_by_median(pred: pd.DataFrame, errors[x_axis_name] = ( errors[['bin', 'n_obs']] .apply( - lambda x: f"{x.bin:0{len_max_bin}} (N={x.n_obs:,d})", axis=1 + lambda x: f"{x.bin:0{len_max_bin}}\n(N={x.n_obs:,d})", axis=1 ) .rename('intensity bin') .astype('category') @@ -98,7 +98,7 @@ def plot_errors_by_median(pred: pd.DataFrame, hue='model', palette=palette, errwidth=errwidth,) - ax.xaxis.set_tick_params(rotation=-90) + ax.xaxis.set_tick_params(rotation=90) return ax, errors From e49c1eb4793e08e69480a63582fd90ce59f74144 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 28 Nov 2023 16:52:38 +0100 Subject: [PATCH 64/70] :art: allow custom display name of feat --- project/01_2_performance_plots.ipynb | 54 +++++++++++++++------------- project/01_2_performance_plots.py | 34 ++++++++++-------- vaep/plotting/errors.py | 8 +++-- 3 files changed, 55 insertions(+), 41 deletions(-) diff --git a/project/01_2_performance_plots.ipynb b/project/01_2_performance_plots.ipynb index 78db92131..a4870a184 100644 --- a/project/01_2_performance_plots.ipynb +++ b/project/01_2_performance_plots.ipynb @@ -36,7 +36,6 @@ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", - "import seaborn as sns\n", "\n", "import vaep\n", "import vaep.imputation\n", @@ -105,7 +104,6 @@ "execution_count": null, "id": "e6e91c6b-20d6-402c-9577-a2bfd8ba592e", "metadata": { - "lines_to_next_cell": 2, "tags": [ "parameters" ] @@ -122,7 +120,8 @@ "models: str = 'Median,CF,DAE,VAE' # picked models to compare (comma separated)\n", "sel_models: str = '' # user defined comparison (comma separated)\n", "# Restrict plotting to top N methods for imputation based on error of validation data, maximum 10\n", - "plot_to_n: int = 5" + "plot_to_n: int = 5\n", + "feat_name_display: str = None # display name for feature name (e.g. 'protein group')" ] }, { @@ -187,6 +186,7 @@ "MIN_FREQ = None\n", "MODELS_PASSED = args.models.split(',')\n", "MODELS = MODELS_PASSED.copy()\n", + "FEAT_NAME_DISPLAY = args.feat_name_display\n", "SEL_MODELS = None\n", "if args.sel_models:\n", " SEL_MODELS = args.sel_models.split(',')" @@ -430,6 +430,9 @@ " split='val',\n", " model_keys=MODELS_PASSED,\n", " shared_columns=[TARGET_COL])\n", + "SAMPLE_ID, FEAT_NAME = pred_val.index.names\n", + "if not FEAT_NAME_DISPLAY:\n", + " FEAT_NAME_DISPLAY = FEAT_NAME\n", "pred_val[MODELS]" ] }, @@ -738,6 +741,7 @@ " ],\n", " feat_medians=data.train_X.median(),\n", " ax=ax,\n", + " feat_name=FEAT_NAME_DISPLAY,\n", " palette=TOP_N_COLOR_PALETTE,\n", " metric_name=METRIC,)\n", "ax.set_ylabel(f\"Average error ({METRIC})\")\n", @@ -784,7 +788,7 @@ " model_keys=MODELS_PASSED,\n", " shared_columns=[TARGET_COL])\n", "pred_test = pred_test.join(freq_feat, on=freq_feat.index.name)\n", - "SAMPLE_ID, FEAT_NAME = pred_test.index.names\n", + "\n", "pred_test" ] }, @@ -1103,7 +1107,7 @@ "source": [ "kwargs = dict(rot=90,\n", " flierprops=dict(markersize=1),\n", - " ylabel=f'correlation per {FEAT_NAME}')\n", + " ylabel=f'correlation per {FEAT_NAME_DISPLAY}')\n", "ax = (corr_per_feat_test\n", " .loc[~too_few_obs, TOP_N_ORDER]\n", " .plot\n", @@ -1255,7 +1259,7 @@ "fig, ax = plt.subplots(figsize=(4, 2))\n", "ax = _to_plot.loc[[feature_names.name]].plot.bar(\n", " rot=0,\n", - " ylabel=f\"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)\",\n", + " ylabel=f\"{METRIC} for {FEAT_NAME_DISPLAY} ({n_in_comparison:,} intensities)\",\n", " # title=f'performance on test data (based on {n_in_comparison:,} measurements)',\n", " color=COLORS_TO_USE,\n", " ax=ax,\n", @@ -1313,6 +1317,7 @@ " ],\n", " feat_medians=data.train_X.median(),\n", " ax=ax,\n", + " feat_name=FEAT_NAME_DISPLAY,\n", " metric_name=METRIC,\n", " palette=COLORS_TO_USE\n", ")\n", @@ -1326,6 +1331,23 @@ "errors_binned" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "b13ecd37", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "(errors_binned\n", + " .set_index(\n", + " ['model', errors_binned.columns[-1]]\n", + " )\n", + " .loc[ORDER_MODELS[0]]\n", + " .sort_values(by=METRIC))" + ] + }, { "cell_type": "markdown", "id": "26370a1a", @@ -1372,7 +1394,7 @@ " fig, ax = plt.subplots(figsize=(4, 2))\n", " ax = _to_plot.loc[[feature_names.name]].plot.bar(\n", " rot=0,\n", - " ylabel=f\"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)\",\n", + " ylabel=f\"{METRIC} for {FEAT_NAME_DISPLAY} ({n_in_comparison:,} intensities)\",\n", " # title=f'performance on test data (based on {n_in_comparison:,} measurements)',\n", " color=vaep.plotting.defaults.assign_colors(\n", " list(k.upper() for k in SEL_MODELS)),\n", @@ -1413,6 +1435,7 @@ " feat_medians=data.train_X.median(),\n", " ax=ax,\n", " metric_name=METRIC,\n", + " feat_name=FEAT_NAME_DISPLAY,\n", " palette=vaep.plotting.defaults.assign_colors(\n", " list(k.upper() for k in SEL_MODELS))\n", " )\n", @@ -1429,23 +1452,6 @@ " display(errors_binned)" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "b13ecd37", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "(errors_binned\n", - " .set_index(\n", - " ['model', errors_binned.columns[-1]]\n", - " )\n", - " .loc[ORDER_MODELS[0]]\n", - " .sort_values(by=METRIC))" - ] - }, { "cell_type": "markdown", "id": "549236ca-9e89-47aa-905c-c97a45d4dc2b", diff --git a/project/01_2_performance_plots.py b/project/01_2_performance_plots.py index 0d1526a09..59e626918 100644 --- a/project/01_2_performance_plots.py +++ b/project/01_2_performance_plots.py @@ -36,7 +36,6 @@ import matplotlib.pyplot as plt import numpy as np import pandas as pd -import seaborn as sns import vaep import vaep.imputation @@ -98,7 +97,7 @@ def build_text(s): sel_models: str = '' # user defined comparison (comma separated) # Restrict plotting to top N methods for imputation based on error of validation data, maximum 10 plot_to_n: int = 5 - +feat_name_display: str = None # display name for feature name (e.g. 'protein group') # %% [markdown] # Some argument transformations @@ -121,6 +120,7 @@ def build_text(s): MIN_FREQ = None MODELS_PASSED = args.models.split(',') MODELS = MODELS_PASSED.copy() +FEAT_NAME_DISPLAY = args.feat_name_display SEL_MODELS = None if args.sel_models: SEL_MODELS = args.sel_models.split(',') @@ -227,6 +227,9 @@ def build_text(s): split='val', model_keys=MODELS_PASSED, shared_columns=[TARGET_COL]) +SAMPLE_ID, FEAT_NAME = pred_val.index.names +if not FEAT_NAME_DISPLAY: + FEAT_NAME_DISPLAY = FEAT_NAME pred_val[MODELS] # %% [markdown] @@ -370,6 +373,7 @@ def build_text(s): ], feat_medians=data.train_X.median(), ax=ax, + feat_name=FEAT_NAME_DISPLAY, palette=TOP_N_COLOR_PALETTE, metric_name=METRIC,) ax.set_ylabel(f"Average error ({METRIC})") @@ -393,7 +397,7 @@ def build_text(s): model_keys=MODELS_PASSED, shared_columns=[TARGET_COL]) pred_test = pred_test.join(freq_feat, on=freq_feat.index.name) -SAMPLE_ID, FEAT_NAME = pred_test.index.names + pred_test # %% [markdown] @@ -553,7 +557,7 @@ def build_text(s): # %% kwargs = dict(rot=90, flierprops=dict(markersize=1), - ylabel=f'correlation per {FEAT_NAME}') + ylabel=f'correlation per {FEAT_NAME_DISPLAY}') ax = (corr_per_feat_test .loc[~too_few_obs, TOP_N_ORDER] .plot @@ -635,7 +639,7 @@ def highlight_min(s, color, tolerence=0.00001): fig, ax = plt.subplots(figsize=(4, 2)) ax = _to_plot.loc[[feature_names.name]].plot.bar( rot=0, - ylabel=f"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)", + ylabel=f"{METRIC} for {FEAT_NAME_DISPLAY} ({n_in_comparison:,} intensities)", # title=f'performance on test data (based on {n_in_comparison:,} measurements)', color=COLORS_TO_USE, ax=ax, @@ -670,6 +674,7 @@ def highlight_min(s, color, tolerence=0.00001): ], feat_medians=data.train_X.median(), ax=ax, + feat_name=FEAT_NAME_DISPLAY, metric_name=METRIC, palette=COLORS_TO_USE ) @@ -682,6 +687,14 @@ def highlight_min(s, color, tolerence=0.00001): errors_binned.to_csv(fname.with_suffix('.csv')) errors_binned +# %% +(errors_binned + .set_index( + ['model', errors_binned.columns[-1]] + ) + .loc[ORDER_MODELS[0]] + .sort_values(by=METRIC)) + # %% [markdown] # ### Custom model selection @@ -715,7 +728,7 @@ def highlight_min(s, color, tolerence=0.00001): fig, ax = plt.subplots(figsize=(4, 2)) ax = _to_plot.loc[[feature_names.name]].plot.bar( rot=0, - ylabel=f"{METRIC} for {feature_names.name} ({n_in_comparison:,} intensities)", + ylabel=f"{METRIC} for {FEAT_NAME_DISPLAY} ({n_in_comparison:,} intensities)", # title=f'performance on test data (based on {n_in_comparison:,} measurements)', color=vaep.plotting.defaults.assign_colors( list(k.upper() for k in SEL_MODELS)), @@ -750,6 +763,7 @@ def highlight_min(s, color, tolerence=0.00001): feat_medians=data.train_X.median(), ax=ax, metric_name=METRIC, + feat_name=FEAT_NAME_DISPLAY, palette=vaep.plotting.defaults.assign_colors( list(k.upper() for k in SEL_MODELS)) ) @@ -765,14 +779,6 @@ def highlight_min(s, color, tolerence=0.00001): # ax.xaxis.set_tick_params(rotation=0) # horizontal display(errors_binned) -# %% -(errors_binned - .set_index( - ['model', errors_binned.columns[-1]] - ) - .loc[ORDER_MODELS[0]] - .sort_values(by=METRIC)) - # %% [markdown] # ### Error by non-decimal number of intensity # diff --git a/vaep/plotting/errors.py b/vaep/plotting/errors.py index 7d6dd790f..5326b9d86 100644 --- a/vaep/plotting/errors.py +++ b/vaep/plotting/errors.py @@ -52,6 +52,7 @@ def plot_errors_by_median(pred: pd.DataFrame, target_col='observed', ax: Axes = None, palette: dict = None, + feat_name: str = None, metric_name: Optional[str] = None, errwidth: float = 1.2) -> tuple[Axes, pd.DataFrame]: # calculate absolute errors @@ -74,9 +75,10 @@ def plot_errors_by_median(pred: pd.DataFrame, errors = errors.join(n_obs, on="bin") - feat_name = feat_medians.index.name - if not feat_name: - feat_name = 'feature' + if feat_name is None: + feat_name = feat_medians.index.name + if not feat_name: + feat_name = 'feature' x_axis_name = f'intensity binned by median of {feat_name}' len_max_bin = len(str(int(errors['bin'].max()))) From 43de8bd0b6c79958be8a1bbd6d89be66ebc1b486 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 5 Dec 2023 09:43:11 +0100 Subject: [PATCH 65/70] :wrench::art: 25MNAR share as default, update path & fontsize - tables for Supp. Data - update plots (fontsize, support) --- project/03_4_join_tables.py | 20 +++++-------------- project/03_5_join_benchmarks.py | 9 ++++----- project/10_1_ald_diff_analysis.ipynb | 11 ++++++---- project/10_1_ald_diff_analysis.py | 9 ++++++--- project/10_4_ald_compare_single_pg.ipynb | 17 +++++++++++++++- project/10_4_ald_compare_single_pg.py | 17 +++++++++++++++- .../plasma/proteinGroups/comparison.yaml | 2 +- .../plasma/proteinGroups/config.yaml | 2 +- .../plasma/proteinGroups/split.yaml | 3 ++- .../single_dev_dataset/evidence/split.yaml | 4 +++- .../evidence_N50/split.yaml | 5 ++++- .../single_dev_dataset/peptides/split.yaml | 4 +++- .../peptides_N50/split.yaml | 4 +++- .../proteinGroups/split.yaml | 4 +++- .../proteinGroups_N50/split.yaml | 2 ++ 15 files changed, 76 insertions(+), 37 deletions(-) diff --git a/project/03_4_join_tables.py b/project/03_4_join_tables.py index f27f29253..404a24bae 100644 --- a/project/03_4_join_tables.py +++ b/project/03_4_join_tables.py @@ -5,31 +5,21 @@ # %% -fname = 'runs/appl_ald_data/plasma/proteinGroups_all/01_2_performance_summary.xlsx' +fname = 'runs/appl_ald_data_2023_11/plasma/proteinGroups/01_2_performance_summary.xlsx' ald_pg_perf = pd.read_excel(fname, sheet_name=-1, index_col=0) -ald_pg_perf.columns = pd.MultiIndex.from_tuples([('ALD data', 'protein groups', x) for x in ald_pg_perf.columns]) +ald_pg_perf.columns = pd.MultiIndex.from_tuples([('ALD protein groups', x) for x in ald_pg_perf.columns]) ald_pg_perf # %% -files = { - 'small HeLa': 'runs/dev_dataset_small/performance_summary.xlsx', - 'large HeLa': 'runs/dev_dataset_large/performance_summary.xlsx', -} -files - -table = [] -for key, file in files.items(): - df = pd.read_excel(file, index_col=0, header=[0, 1]) - df.columns = pd.MultiIndex.from_tuples([(key, *x) for x in df.columns]) - table.append(df) - +file = 'runs/mnar_mcar/all_results.xlsx' +table = [pd.read_excel(file, index_col=0, header=[0, 1])] table.append(ald_pg_perf) table = pd.concat(table, axis=1) table # %% order = (table - .loc[:, pd.IndexSlice[:, :, 'val']] + .loc[:, pd.IndexSlice[ :, 'val']] .mean(axis=1) .sort_values() ) diff --git a/project/03_5_join_benchmarks.py b/project/03_5_join_benchmarks.py index 493dff1b1..1db7eeb73 100644 --- a/project/03_5_join_benchmarks.py +++ b/project/03_5_join_benchmarks.py @@ -9,8 +9,8 @@ root_folder: str = 'runs/dev_dataset_small' # large -# root_folder: str = 'runs/dev_dataset_large' -# root_folder: str = 'runs/appl_ald_data/plasma' +root_folder: str = 'runs/mnar_mcar' +root_folder: str = 'runs/appl_ald_data_2023_11/plasma' # %% root_folder = Path(root_folder) @@ -81,9 +81,8 @@ def find_tsv_benchmarks(root_folder: Path): # %% runtime_dumps = [ - 'runs/dev_dataset_large/runtimes.xlsx', - 'runs/dev_dataset_small/runtimes.xlsx', - 'runs/appl_ald_data/plasma/runtimes.xlsx' + 'runs/mnar_mcar/runtimes.xlsx', + 'runs/appl_ald_data_2023_11/plasma/runtimes.xlsx' ] runtime_dumps = [pd.read_excel(fname, index_col=0) for fname in runtime_dumps] runtime_dumps = pd.concat(runtime_dumps, axis=1) diff --git a/project/10_1_ald_diff_analysis.ipynb b/project/10_1_ald_diff_analysis.ipynb index 95ca6552e..b25564941 100644 --- a/project/10_1_ald_diff_analysis.ipynb +++ b/project/10_1_ald_diff_analysis.ipynb @@ -18,8 +18,10 @@ "metadata": {}, "outputs": [], "source": [ + "import logging\n", "from pathlib import Path\n", "import matplotlib.pyplot as plt\n", + "from IPython.display import display\n", "\n", "import pandas as pd\n", "\n", @@ -31,7 +33,8 @@ "\n", "import vaep.nb\n", "\n", - "logger = vaep.logging.setup_nb_logger()" + "logger = vaep.logging.setup_nb_logger()\n", + "logging.getLogger('fontTools').setLevel(logging.WARNING)" ] }, { @@ -302,7 +305,7 @@ "logger.info(fname)\n", "feat_freq_observed.to_csv(fname)\n", "ax = feat_freq_observed.sort_values().plot(marker='.', rot=90)\n", - "_ = ax.set_xticklabels([l.get_text().split(';')[0] for l in ax.get_xticklabels()])" + "_ = ax.set_xticklabels([l_.get_text().split(';')[0] for l_ in ax.get_xticklabels()])" ] }, { @@ -466,7 +469,7 @@ " sharex=True):\n", " \"\"\"Plots distributions of intensities provided as dictionary of labels to pd.Series.\"\"\"\n", " series_ = [observed, imputation] if imputation is not None else [observed]\n", - " min_bin, max_bin = vaep.plotting.data.get_min_max_iterable(series_)\n", + " min_bin, max_bin = vaep.plotting.data.get_min_max_iterable([observed])\n", "\n", " if imputation is not None:\n", " fig, axes = plt.subplots(len(series_), figsize=figsize, sharex=sharex)\n", @@ -497,7 +500,7 @@ " return fig\n", "\n", "\n", - "vaep.plotting.make_large_descriptors(5)\n", + "vaep.plotting.make_large_descriptors(6)\n", "fig = plot_distributions(observed,\n", " imputation=pred_real_na,\n", " model_key=args.model_key, figsize=(2.5, 2))\n", diff --git a/project/10_1_ald_diff_analysis.py b/project/10_1_ald_diff_analysis.py index 15893ff5c..1258de220 100644 --- a/project/10_1_ald_diff_analysis.py +++ b/project/10_1_ald_diff_analysis.py @@ -21,8 +21,10 @@ # (default: draw from shifted normal distribution. short RSN) # %% +import logging from pathlib import Path import matplotlib.pyplot as plt +from IPython.display import display import pandas as pd @@ -35,6 +37,7 @@ import vaep.nb logger = vaep.logging.setup_nb_logger() +logging.getLogger('fontTools').setLevel(logging.WARNING) # %% # catch passed parameters @@ -174,7 +177,7 @@ logger.info(fname) feat_freq_observed.to_csv(fname) ax = feat_freq_observed.sort_values().plot(marker='.', rot=90) -_ = ax.set_xticklabels([l.get_text().split(';')[0] for l in ax.get_xticklabels()]) +_ = ax.set_xticklabels([l_.get_text().split(';')[0] for l_ in ax.get_xticklabels()]) # %% [markdown] # ## ALD study approach using all measurments @@ -266,7 +269,7 @@ def plot_distributions(observed: pd.Series, sharex=True): """Plots distributions of intensities provided as dictionary of labels to pd.Series.""" series_ = [observed, imputation] if imputation is not None else [observed] - min_bin, max_bin = vaep.plotting.data.get_min_max_iterable(series_) + min_bin, max_bin = vaep.plotting.data.get_min_max_iterable([observed]) if imputation is not None: fig, axes = plt.subplots(len(series_), figsize=figsize, sharex=sharex) @@ -297,7 +300,7 @@ def plot_distributions(observed: pd.Series, return fig -vaep.plotting.make_large_descriptors(5) +vaep.plotting.make_large_descriptors(6) fig = plot_distributions(observed, imputation=pred_real_na, model_key=args.model_key, figsize=(2.5, 2)) diff --git a/project/10_4_ald_compare_single_pg.ipynb b/project/10_4_ald_compare_single_pg.ipynb index 3de5bb57b..fe947a33b 100644 --- a/project/10_4_ald_compare_single_pg.ipynb +++ b/project/10_4_ald_compare_single_pg.ipynb @@ -337,7 +337,22 @@ "(qvalues\n", " .loc[feat_idx_w_diff]\n", " .sort_values(('None', 'qvalue'))\n", - " .to_excel(writer, sheet_name='qvalues_diff'))\n", + " .to_excel(writer, sheet_name='qvalues_diff')\n", + " )\n", + "\n", + "(qvalues\n", + " .loc[feat_idx_w_diff]\n", + " .loc[mask_common] # mask automatically aligned\n", + " .sort_values(('None', 'qvalue'))\n", + " .to_excel(writer, sheet_name='qvalues_diff_common')\n", + " )\n", + "\n", + "(qvalues\n", + " .loc[feat_idx_w_diff]\n", + " .loc[~mask_common] # mask automatically aligned\n", + " .sort_values(('None', 'qvalue'))\n", + " .to_excel(writer, sheet_name='qvalues_diff_new')\n", + " )\n", "writer.close()" ] }, diff --git a/project/10_4_ald_compare_single_pg.py b/project/10_4_ald_compare_single_pg.py index 96ba6f7c6..8f8fa5da0 100644 --- a/project/10_4_ald_compare_single_pg.py +++ b/project/10_4_ald_compare_single_pg.py @@ -191,7 +191,22 @@ (qvalues .loc[feat_idx_w_diff] .sort_values(('None', 'qvalue')) - .to_excel(writer, sheet_name='qvalues_diff')) + .to_excel(writer, sheet_name='qvalues_diff') + ) + +(qvalues + .loc[feat_idx_w_diff] + .loc[mask_common] # mask automatically aligned + .sort_values(('None', 'qvalue')) + .to_excel(writer, sheet_name='qvalues_diff_common') + ) + +(qvalues + .loc[feat_idx_w_diff] + .loc[~mask_common] # mask automatically aligned + .sort_values(('None', 'qvalue')) + .to_excel(writer, sheet_name='qvalues_diff_new') + ) writer.close() # %% [markdown] diff --git a/project/config/appl_ald_data/plasma/proteinGroups/comparison.yaml b/project/config/appl_ald_data/plasma/proteinGroups/comparison.yaml index c2f01d2b8..dd490ea0c 100644 --- a/project/config/appl_ald_data/plasma/proteinGroups/comparison.yaml +++ b/project/config/appl_ald_data/plasma/proteinGroups/comparison.yaml @@ -1,4 +1,4 @@ -folder_experiment: runs/appl_ald_data/plasma/proteinGroups +folder_experiment: runs/appl_ald_data_2023_11/plasma/proteinGroups out_folder: diff_analysis # subfolder of experiment folder fn_rawfile_metadata: "data/ALD_study/processed/raw_meta.csv" make_plots: True diff --git a/project/config/appl_ald_data/plasma/proteinGroups/config.yaml b/project/config/appl_ald_data/plasma/proteinGroups/config.yaml index 83b6a5ded..c17dc8e13 100644 --- a/project/config/appl_ald_data/plasma/proteinGroups/config.yaml +++ b/project/config/appl_ald_data/plasma/proteinGroups/config.yaml @@ -1,7 +1,7 @@ # config for Snakefile_v1 config_split: config/appl_ald_data/plasma/proteinGroups/split.yaml config_train: config/appl_ald_data/plasma/proteinGroups/train_{model}.yaml -folder_experiment: runs/appl_ald_data/plasma/proteinGroups +folder_experiment: runs/appl_ald_data_2023_11/plasma/proteinGroups fn_rawfile_metadata: data/ALD_study/processed/raw_meta.csv file_format: pkl models: diff --git a/project/config/appl_ald_data/plasma/proteinGroups/split.yaml b/project/config/appl_ald_data/plasma/proteinGroups/split.yaml index d1737df8e..e0e85bcc0 100644 --- a/project/config/appl_ald_data/plasma/proteinGroups/split.yaml +++ b/project/config/appl_ald_data/plasma/proteinGroups/split.yaml @@ -3,4 +3,5 @@ fn_rawfile_metadata: data/ALD_study/processed/raw_meta.csv sample_completeness: 0.5 min_RT_time: 20 column_names: - - PG.ProteinAccessions \ No newline at end of file + - PG.ProteinAccessions +frac_mnar: 0.25 diff --git a/project/config/single_dev_dataset/evidence/split.yaml b/project/config/single_dev_dataset/evidence/split.yaml index e766c0b62..8b85e3ad0 100644 --- a/project/config/single_dev_dataset/evidence/split.yaml +++ b/project/config/single_dev_dataset/evidence/split.yaml @@ -2,4 +2,6 @@ FN_INTENSITIES: data/dev_datasets/df_intensities_evidence_long/Q_Exactive_HF_X_O fn_rawfile_metadata: data/dev_datasets/df_intensities_evidence_long/metadata.csv sample_completeness: 0.5 min_RT_time: 120 -column_names: null \ No newline at end of file +column_names: null +frac_mnar: 0.25 +frac_non_train: 0.1 diff --git a/project/config/single_dev_dataset/evidence_N50/split.yaml b/project/config/single_dev_dataset/evidence_N50/split.yaml index b72f99608..369b70aa8 100644 --- a/project/config/single_dev_dataset/evidence_N50/split.yaml +++ b/project/config/single_dev_dataset/evidence_N50/split.yaml @@ -4,4 +4,7 @@ min_RT_time: 120 select_N: 50 column_names: null index_col: 0 -meta_date_col: Content Creation Date \ No newline at end of file +meta_date_col: Content Creation Date +frac_mnar: 0.25 +frac_non_train: 0.1 + diff --git a/project/config/single_dev_dataset/peptides/split.yaml b/project/config/single_dev_dataset/peptides/split.yaml index 732957cb3..5c5c53d38 100644 --- a/project/config/single_dev_dataset/peptides/split.yaml +++ b/project/config/single_dev_dataset/peptides/split.yaml @@ -2,4 +2,6 @@ FN_INTENSITIES: data/dev_datasets/df_intensities_peptides_long/Q_Exactive_HF_X_O fn_rawfile_metadata: data/dev_datasets/df_intensities_peptides_long/metadata.csv sample_completeness: 0.5 min_RT_time: 120 -column_names: null \ No newline at end of file +column_names: null +frac_mnar: 0.25 +frac_non_train: 0.1 diff --git a/project/config/single_dev_dataset/peptides_N50/split.yaml b/project/config/single_dev_dataset/peptides_N50/split.yaml index 901cc2a96..b6f68b86c 100644 --- a/project/config/single_dev_dataset/peptides_N50/split.yaml +++ b/project/config/single_dev_dataset/peptides_N50/split.yaml @@ -4,4 +4,6 @@ min_RT_time: 120 select_N: 50 column_names: null index_col: 0 -meta_date_col: Content Creation Date \ No newline at end of file +meta_date_col: Content Creation Date +frac_mnar: 0.25 +frac_non_train: 0.1 diff --git a/project/config/single_dev_dataset/proteinGroups/split.yaml b/project/config/single_dev_dataset/proteinGroups/split.yaml index 675f1b785..414b9a887 100644 --- a/project/config/single_dev_dataset/proteinGroups/split.yaml +++ b/project/config/single_dev_dataset/proteinGroups/split.yaml @@ -1,3 +1,5 @@ FN_INTENSITIES: data/dev_datasets/df_intensities_proteinGroups_long/Q_Exactive_HF_X_Orbitrap_6070.pkl sample_completeness: 0.5 -min_RT_time: 120 \ No newline at end of file +min_RT_time: 120 +frac_mnar: 0.25 +frac_non_train: 0.1 diff --git a/project/config/single_dev_dataset/proteinGroups_N50/split.yaml b/project/config/single_dev_dataset/proteinGroups_N50/split.yaml index 14ed36cdf..10287480f 100644 --- a/project/config/single_dev_dataset/proteinGroups_N50/split.yaml +++ b/project/config/single_dev_dataset/proteinGroups_N50/split.yaml @@ -7,3 +7,5 @@ column_names: - Gene Names index_col: 0 meta_date_col: Content Creation Date +frac_mnar: 0.25 +frac_non_train: 0.1 From bbe068e4b72e5d99680e57868444711e9df5436d Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 5 Dec 2023 09:45:58 +0100 Subject: [PATCH 66/70] :art::wrench: Update comp. with subsetted data - use a share of 25% MNAR in removed data - use a share of 25% MNAR in comparison - update figures for publication (names, label, fontsize, etc) --- project/10_7_ald_reduced_dataset_plots.ipynb | 87 +++++++++---------- project/10_7_ald_reduced_dataset_plots.py | 57 ++++++------ .../proteinGroups_80%_dataset/config.yaml | 24 ----- .../comparison.yaml | 23 ++--- .../proteinGroups_80perc_dataset/config.yaml | 38 ++++++++ .../split.yaml | 5 +- 6 files changed, 123 insertions(+), 111 deletions(-) delete mode 100644 project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/config.yaml rename project/config/appl_ald_data/plasma/{proteinGroups_80%_dataset => proteinGroups_80perc_dataset}/comparison.yaml (68%) create mode 100644 project/config/appl_ald_data/plasma/proteinGroups_80perc_dataset/config.yaml rename project/config/appl_ald_data/plasma/{proteinGroups_80%_dataset => proteinGroups_80perc_dataset}/split.yaml (74%) diff --git a/project/10_7_ald_reduced_dataset_plots.ipynb b/project/10_7_ald_reduced_dataset_plots.ipynb index 3c6f8b974..65400732d 100644 --- a/project/10_7_ald_reduced_dataset_plots.ipynb +++ b/project/10_7_ald_reduced_dataset_plots.ipynb @@ -21,9 +21,19 @@ "\n", "import vaep\n", "plt.rcParams['figure.figsize'] = [4, 2] # [16.0, 7.0] , [4, 3]\n", - "vaep.plotting.make_large_descriptors(5)\n", + "vaep.plotting.make_large_descriptors(6)\n", + "\n", + "\n", + "NONE_COL_NAME = 'No imputation\\n(None)'\n", + "col_mapper = {'None':\n", + " NONE_COL_NAME}\n", + "# overwrite for now to align with Fig. 3\n", + "ORDER_MODELS = ['DAE', 'VAE', 'TRKNN', 'RF', 'CF', 'Median', 'QRILC', NONE_COL_NAME]\n", + "REF_MODEL = 'None (100%)'\n", + "CUTOFF = 0.05\n", "\n", "COLORS_TO_USE_MAPPTING = vaep.plotting.defaults.color_model_mapping\n", + "COLORS_TO_USE_MAPPTING[NONE_COL_NAME] = COLORS_TO_USE_MAPPTING['None']\n", "\n", "\n", "def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05,\n", @@ -61,7 +71,7 @@ "metadata": {}, "outputs": [], "source": [ - "out_folder = 'runs/appl_ald_data/plasma/proteinGroups_80%_dataset/diff_analysis/kleiner/'\n", + "out_folder = 'runs/appl_ald_data_2023_11/plasma/proteinGroups_80perc_25MNAR/diff_analysis/kleiner/'\n", "out_folder = Path(out_folder)" ] }, @@ -75,43 +85,19 @@ "files_out = dict()\n", "fname = out_folder / 'ald_reduced_dataset_plots.xlsx'\n", "files_out[fname.name] = fname.as_posix()\n", - "writer = pd.ExcelWriter(fname)" - ] - }, - { - "cell_type": "markdown", - "id": "e37f0980-80d9-4835-b814-91cc9cac26f9", - "metadata": {}, - "source": [ - "Ordering of model and reference model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1d745bfc", - "metadata": {}, - "outputs": [], - "source": [ - "ORDER_MODELS = pd.read_csv(\n", - " out_folder.parent.parent / 'figures/performance_test.csv',\n", - " index_col=0\n", - ").index.to_list()\n", - "ORDER_MODELS" + "writer = pd.ExcelWriter(fname)\n", + "\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "f4c6a074", - "metadata": {}, + "id": "cd7ab8d5", + "metadata": { + "lines_to_next_cell": 2 + }, "outputs": [], - "source": [ - "# overwrite for now to align with Fig. 3\n", - "ORDER_MODELS = ['DAE', 'VAE', 'rf', 'CF', 'KNN', 'Median', 'None']\n", - "REF_MODEL = 'None (100%)'\n", - "CUTOFF = 0.05" - ] + "source": [] }, { "cell_type": "markdown", @@ -128,7 +114,10 @@ "metadata": {}, "outputs": [], "source": [ - "da_target = pd.read_pickle(out_folder / 'equality_rejected_target.pkl')\n", + "da_target = (pd\n", + " .read_pickle(out_folder / 'equality_rejected_target.pkl').\n", + " rename(col_mapper, axis=1)\n", + " )\n", "da_target.describe()" ] }, @@ -136,12 +125,13 @@ "cell_type": "code", "execution_count": null, "id": "e8df4a84", - "metadata": { - "lines_to_next_cell": 2 - }, + "metadata": {}, "outputs": [], "source": [ - "qvalues = pd.read_pickle(out_folder / 'qvalues_target.pkl')\n", + "qvalues = (pd\n", + " .read_pickle(out_folder / 'qvalues_target.pkl')\n", + " .rename(col_mapper, axis=1)\n", + " )\n", "qvalues" ] }, @@ -189,7 +179,7 @@ "source": [ "qvalues_sel = (qvalues\n", " .loc[feat_idx_w_diff]\n", - " .sort_values(('None', 'qvalue')\n", + " .sort_values((NONE_COL_NAME, 'qvalue')\n", " ))" ] }, @@ -220,7 +210,7 @@ "outputs": [], "source": [ "mask_lost_sign = (\n", - " (da_target_sel['None'] == False)\n", + " (da_target_sel[NONE_COL_NAME] == False)\n", " & (da_target_sel[REF_MODEL])\n", ")\n", "sel = qvalues_sel.loc[mask_lost_sign.squeeze()]\n", @@ -248,7 +238,7 @@ ").droplevel(-1, axis=1)\n", ")\n", "da_target_sel_counts = vaep.pandas.combine_value_counts(da_target_sel_counts)\n", - "ax = da_target_sel_counts.T.plot.bar()\n", + "ax = da_target_sel_counts.T.plot.bar(ylabel='count')\n", "ax.locator_params(axis='y', integer=True)\n", "fname = out_folder / 'lost_signal_da_counts.pdf'\n", "files_out[fname.name] = fname.as_posix()\n", @@ -268,7 +258,8 @@ " x=REF_MODEL,\n", " y=ORDER_MODELS,\n", " cutoff=CUTOFF)\n", - "ax.set_xlim(-0.0005, CUTOFF + 0.0005)\n", + "ax.set_xlim(-0.0005, CUTOFF + 0.015)\n", + "ax.legend(loc='upper right')\n", "ax.set_xlabel(\"q-value using 100% of the data without imputation\")\n", "ax.set_ylabel(\"q-value using 80% of the data\")\n", "fname = out_folder / 'lost_signal_qvalues.pdf'\n", @@ -292,7 +283,7 @@ "outputs": [], "source": [ "mask_gained_signal = (\n", - " (da_target_sel['None'])\n", + " (da_target_sel[NONE_COL_NAME])\n", " & (da_target_sel[REF_MODEL] == False)\n", ")\n", "sel = qvalues_sel.loc[mask_gained_signal.squeeze()]\n", @@ -318,7 +309,7 @@ ").droplevel(-1, axis=1)\n", ")\n", "da_target_sel_counts = vaep.pandas.combine_value_counts(da_target_sel_counts)\n", - "ax = da_target_sel_counts.T.plot.bar()\n", + "ax = da_target_sel_counts.T.plot.bar(ylabel='count')\n", "ax.locator_params(axis='y', integer=True)\n", "fname = out_folder / 'gained_signal_da_counts.pdf'\n", "files_out[fname.name] = fname.as_posix()\n", @@ -335,10 +326,10 @@ "ax = plot_qvalues(sel,\n", " x=REF_MODEL,\n", " y=ORDER_MODELS)\n", - "ax.set_xlim(CUTOFF - 0.01, sel[REF_MODEL].max() + 0.005)\n", + "# ax.set_xlim(CUTOFF - 0.005, sel[REF_MODEL].max() + 0.005)\n", "ax.set_xlabel(\"q-value using 100% of the data without imputation\")\n", - "ax.set_ylabel(\"q-value using 80%\")\n", - "ax.legend(loc='upper center')\n", + "ax.set_ylabel(\"q-value using 80% of the data\")\n", + "ax.legend(loc='upper right')\n", "fname = out_folder / 'gained_signal_qvalues.pdf'\n", "files_out[fname.name] = fname.as_posix()\n", "vaep.savefig(ax.figure, fname)" @@ -366,7 +357,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cd7ab8d5", + "id": "47e6afe8", "metadata": {}, "outputs": [], "source": [] diff --git a/project/10_7_ald_reduced_dataset_plots.py b/project/10_7_ald_reduced_dataset_plots.py index e62ffe87a..af0739fec 100644 --- a/project/10_7_ald_reduced_dataset_plots.py +++ b/project/10_7_ald_reduced_dataset_plots.py @@ -8,9 +8,19 @@ import vaep plt.rcParams['figure.figsize'] = [4, 2] # [16.0, 7.0] , [4, 3] -vaep.plotting.make_large_descriptors(5) +vaep.plotting.make_large_descriptors(6) + + +NONE_COL_NAME = 'No imputation\n(None)' +col_mapper = {'None': + NONE_COL_NAME} +# overwrite for now to align with Fig. 3 +ORDER_MODELS = ['DAE', 'VAE', 'TRKNN', 'RF', 'CF', 'Median', 'QRILC', NONE_COL_NAME] +REF_MODEL = 'None (100%)' +CUTOFF = 0.05 COLORS_TO_USE_MAPPTING = vaep.plotting.defaults.color_model_mapping +COLORS_TO_USE_MAPPTING[NONE_COL_NAME] = COLORS_TO_USE_MAPPTING['None'] def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, @@ -34,7 +44,7 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, # %% [markdown] # DA analysis # %% -out_folder = 'runs/appl_ald_data/plasma/proteinGroups_80%_dataset/diff_analysis/kleiner/' +out_folder = 'runs/appl_ald_data_2023_11/plasma/proteinGroups_80perc_25MNAR/diff_analysis/kleiner/' out_folder = Path(out_folder) # %% @@ -43,34 +53,28 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, files_out[fname.name] = fname.as_posix() writer = pd.ExcelWriter(fname) -# %% [markdown] -# Ordering of model and reference model -# %% -ORDER_MODELS = pd.read_csv( - out_folder.parent.parent / 'figures/performance_test.csv', - index_col=0 -).index.to_list() -ORDER_MODELS # %% -# overwrite for now to align with Fig. 3 -ORDER_MODELS = ['DAE', 'VAE', 'rf', 'CF', 'KNN', 'Median', 'None'] -REF_MODEL = 'None (100%)' -CUTOFF = 0.05 + # %% [markdown] # Load dumps # %% -da_target = pd.read_pickle(out_folder / 'equality_rejected_target.pkl') +da_target = (pd + .read_pickle(out_folder / 'equality_rejected_target.pkl'). + rename(col_mapper, axis=1) + ) da_target.describe() # %% -qvalues = pd.read_pickle(out_folder / 'qvalues_target.pkl') +qvalues = (pd + .read_pickle(out_folder / 'qvalues_target.pkl') + .rename(col_mapper, axis=1) + ) qvalues - # %% [markdown] # take only those with different decisions @@ -87,7 +91,7 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, # %% qvalues_sel = (qvalues .loc[feat_idx_w_diff] - .sort_values(('None', 'qvalue') + .sort_values((NONE_COL_NAME, 'qvalue') )) @@ -100,7 +104,7 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, # %% mask_lost_sign = ( - (da_target_sel['None'] == False) + (da_target_sel[NONE_COL_NAME] == False) & (da_target_sel[REF_MODEL]) ) sel = qvalues_sel.loc[mask_lost_sign.squeeze()] @@ -121,7 +125,7 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, ).droplevel(-1, axis=1) ) da_target_sel_counts = vaep.pandas.combine_value_counts(da_target_sel_counts) -ax = da_target_sel_counts.T.plot.bar() +ax = da_target_sel_counts.T.plot.bar(ylabel='count') ax.locator_params(axis='y', integer=True) fname = out_folder / 'lost_signal_da_counts.pdf' files_out[fname.name] = fname.as_posix() @@ -132,7 +136,8 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, x=REF_MODEL, y=ORDER_MODELS, cutoff=CUTOFF) -ax.set_xlim(-0.0005, CUTOFF + 0.0005) +ax.set_xlim(-0.0005, CUTOFF + 0.015) +ax.legend(loc='upper right') ax.set_xlabel("q-value using 100% of the data without imputation") ax.set_ylabel("q-value using 80% of the data") fname = out_folder / 'lost_signal_qvalues.pdf' @@ -145,7 +150,7 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, # %% mask_gained_signal = ( - (da_target_sel['None']) + (da_target_sel[NONE_COL_NAME]) & (da_target_sel[REF_MODEL] == False) ) sel = qvalues_sel.loc[mask_gained_signal.squeeze()] @@ -164,7 +169,7 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, ).droplevel(-1, axis=1) ) da_target_sel_counts = vaep.pandas.combine_value_counts(da_target_sel_counts) -ax = da_target_sel_counts.T.plot.bar() +ax = da_target_sel_counts.T.plot.bar(ylabel='count') ax.locator_params(axis='y', integer=True) fname = out_folder / 'gained_signal_da_counts.pdf' files_out[fname.name] = fname.as_posix() @@ -174,10 +179,10 @@ def plot_qvalues(df, x: str, y: list, ax=None, cutoff=0.05, ax = plot_qvalues(sel, x=REF_MODEL, y=ORDER_MODELS) -ax.set_xlim(CUTOFF - 0.01, sel[REF_MODEL].max() + 0.005) +# ax.set_xlim(CUTOFF - 0.005, sel[REF_MODEL].max() + 0.005) ax.set_xlabel("q-value using 100% of the data without imputation") -ax.set_ylabel("q-value using 80%") -ax.legend(loc='upper center') +ax.set_ylabel("q-value using 80% of the data") +ax.legend(loc='upper right') fname = out_folder / 'gained_signal_qvalues.pdf' files_out[fname.name] = fname.as_posix() vaep.savefig(ax.figure, fname) diff --git a/project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/config.yaml b/project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/config.yaml deleted file mode 100644 index 75bde92ba..000000000 --- a/project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/config.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# config for Snakefile_v1 -config_split: config/appl_ald_data/plasma/proteinGroups_80%_dataset/split.yaml -config_train: config/appl_ald_data/plasma/proteinGroups/train_{model}.yaml -folder_experiment: runs/appl_ald_data/plasma/proteinGroups_80%_dataset -fn_rawfile_metadata: 'data/ALD_study/processed/raw_meta.csv' -file_format: pkl -models: - - RSN - - Median # maps to median on file system? - - CF - - DAE - - VAE - - KNN -NAGuideR_methods: - # - lls - - knnmethod - # - seqknn # error - - rf - # - impseq # error - - qrilc - - minprob - - mindet - - svdmethod - # - mice-norm # stopped after 8h \ No newline at end of file diff --git a/project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/comparison.yaml b/project/config/appl_ald_data/plasma/proteinGroups_80perc_dataset/comparison.yaml similarity index 68% rename from project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/comparison.yaml rename to project/config/appl_ald_data/plasma/proteinGroups_80perc_dataset/comparison.yaml index d1a4ab35a..785724574 100644 --- a/project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/comparison.yaml +++ b/project/config/appl_ald_data/plasma/proteinGroups_80perc_dataset/comparison.yaml @@ -1,7 +1,7 @@ -folder_experiment: runs/appl_ald_data/plasma/proteinGroups_80%_dataset +folder_experiment: runs/appl_ald_data_2023_11/plasma/proteinGroups_80perc_25MNAR out_folder: diff_analysis # subfolder of experiment folder -fn_rawfile_metadata: 'data/ALD_study/processed/raw_meta.csv' -covar: +fn_rawfile_metadata: "data/ALD_study/processed/raw_meta.csv" +covar: kleiner: age,bmi,gender_num,nas_steatosis_ordinal,abstinent_num inflammation: age,bmi,gender_num,nas_steatosis_ordinal,abstinent_num steatosis: age,bmi,gender_num,abstinent_num,kleiner,nas_inflam @@ -17,13 +17,14 @@ f_annotations: data/ALD_study/processed/ald_plasma_proteinGroups_id_mappings.csv annotaitons_gene_col: PG.Genes baseline: RSN # ! needs analysis full dataset: -ref_method_score: runs/appl_ald_data/plasma/proteinGroups/diff_analysis/kleiner/scores/diff_analysis_scores_None.pkl +ref_method_score: runs/appl_ald_data_2023_11/plasma/proteinGroups/diff_analysis/kleiner/scores/diff_analysis_scores_None.pkl # ! # needs to be false if ref method is specified in current setup -make_plots: False +make_plots: False methods: - - Median - - CF - - DAE - - VAE - - rf - - KNN + - Median + - CF + - DAE + - VAE + - QRILC + - TRKNN + - RF diff --git a/project/config/appl_ald_data/plasma/proteinGroups_80perc_dataset/config.yaml b/project/config/appl_ald_data/plasma/proteinGroups_80perc_dataset/config.yaml new file mode 100644 index 000000000..37177c1c2 --- /dev/null +++ b/project/config/appl_ald_data/plasma/proteinGroups_80perc_dataset/config.yaml @@ -0,0 +1,38 @@ +# config for Snakefile_v1 +config_split: config/appl_ald_data/plasma/proteinGroups_80perc_dataset/split.yaml +config_train: config/appl_ald_data/plasma/proteinGroups/train_{model}.yaml +folder_experiment: runs/appl_ald_data_2023_11/plasma/proteinGroups_80perc_25MNAR +fn_rawfile_metadata: "data/ALD_study/processed/raw_meta.csv" +file_format: pkl +models: + - RSN + - Median # maps to median on file system? + - CF + - DAE + - VAE + - KNN +NAGuideR_methods: + - BPCA + - COLMEDIAN + - GSIMP # slow + - IMPSEQ + - IMPSEQROB + - IRM + - KNN_IMPUTE + - LLS + # - MICE-CART # stopped after 24h + # - MICE-NORM # stopped after 24h + - MINDET + - MINIMUM + - MINPROB + - MLE + - MSIMPUTE + - MSIMPUTE_MNAR + - PI + - QRILC + - RF + - ROWMEDIAN + # - SEQKNN # Error in x[od, ismiss, drop = FALSE]: subscript out of bounds + - SVDMETHOD + - TRKNN + - ZERO diff --git a/project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/split.yaml b/project/config/appl_ald_data/plasma/proteinGroups_80perc_dataset/split.yaml similarity index 74% rename from project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/split.yaml rename to project/config/appl_ald_data/plasma/proteinGroups_80perc_dataset/split.yaml index 3d4ef529e..b28fafef9 100644 --- a/project/config/appl_ald_data/plasma/proteinGroups_80%_dataset/split.yaml +++ b/project/config/appl_ald_data/plasma/proteinGroups_80perc_dataset/split.yaml @@ -1,6 +1,7 @@ -FN_INTENSITIES: data/ALD_study/processed/ald_plasma_proteinGroups_0.80.pkl +FN_INTENSITIES: data/ALD_study/processed/ald_plasma_proteinGroups_80perc_25MNAR.pkl fn_rawfile_metadata: data/ALD_study/processed/raw_meta.csv sample_completeness: 0.3 min_RT_time: 20 column_names: - - PG.ProteinAccessions \ No newline at end of file + - PG.ProteinAccessions +frac_mnar: 0.25 From 052ed787dcd38e02209b2cc60a7ad8e321f7755d Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 5 Dec 2023 09:49:10 +0100 Subject: [PATCH 67/70] :wrench: update exp.: repeated runs of full ald data - dump config --- .../plasma/proteinGroups/config_reps.yaml | 17 +++++++++++++++++ .../Snakefile_ald_comparison_repeated.smk | 8 ++++---- 2 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 project/config/appl_ald_data/plasma/proteinGroups/config_reps.yaml diff --git a/project/config/appl_ald_data/plasma/proteinGroups/config_reps.yaml b/project/config/appl_ald_data/plasma/proteinGroups/config_reps.yaml new file mode 100644 index 000000000..77ab1b896 --- /dev/null +++ b/project/config/appl_ald_data/plasma/proteinGroups/config_reps.yaml @@ -0,0 +1,17 @@ +# config for Snakefile_v1 +config_split: config/appl_ald_data/plasma/proteinGroups/split.yaml +config_train: config/appl_ald_data/plasma/proteinGroups/train_{model}.yaml +folder_experiment: runs/appl_ald_data_2023_11/plasma/proteinGroups +fn_rawfile_metadata: data/ALD_study/processed/raw_meta.csv +file_format: pkl +models: + - RSN + - Median # maps to median on file system? + - CF + - DAE + - VAE + - KNN +NAGuideR_methods: + - QRILC + - RF + - TRKNN diff --git a/project/workflow/Snakefile_ald_comparison_repeated.smk b/project/workflow/Snakefile_ald_comparison_repeated.smk index 87498d9a6..b4aa9299a 100644 --- a/project/workflow/Snakefile_ald_comparison_repeated.smk +++ b/project/workflow/Snakefile_ald_comparison_repeated.smk @@ -3,7 +3,7 @@ Try to execute several time the same Snakemake workflow using another Snakemake - one by one? (-> one process at a time?) """ -folder_experiment = "runs/appl_ald_data/plasma/proteinGroups/reps" +folder_experiment = "runs/appl_ald_data_2023_11/reps/plasma/proteinGroups" folder_run = folder_experiment + "/run_{run}" out_folder = folder_run + "/{sub_folder}/{target}" @@ -44,7 +44,7 @@ rule compare_repetitions: rule run_comparison_workflow: input: - f"{folder_run}/figures/errors_binned_by_int_test.pdf", + f"{folder_run}/figures/2_1_test_errors_binned_by_feat_medians.pdf", output: excel=f"{out_folder}/equality_rejected_target.pkl", qvalues=f"{out_folder}/qvalues_target.pkl", @@ -62,9 +62,9 @@ rule run_comparison_workflow: rule run_models: output: - f"{folder_run}/figures/errors_binned_by_int_test.pdf", + f"{folder_run}/figures/2_1_test_errors_binned_by_feat_medians.pdf", params: - configfile="config/appl_ald_data/plasma/proteinGroups/config.yaml", + configfile="config/appl_ald_data/plasma/proteinGroups/config_reps.yaml", folder_experiment=folder_run, shell: "snakemake --configfile {params.configfile}" From 49d628ba788db6038093760fa2e2365363d29df3 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 7 Dec 2023 13:33:17 +0100 Subject: [PATCH 68/70] :art::bug: update overfitting analysis (25MNAR) - :bug: remove metadata fpath from train_X.yaml - also run KNN comp. with workflow v2 with a share of 25MNAR --- project/03_1_best_models_comparison.ipynb | 17 ++++++++-- project/03_1_best_models_comparison.py | 10 ++++-- .../knn_comparison/hela_pgs_large/config.yaml | 32 +++++++++---------- .../knn_comparison/hela_pgs_large/split.yaml | 2 +- project/config/permuted_dataset/config.yaml | 18 +++++------ project/config/permuted_dataset/split.yaml | 1 + project/config/repeat_best/split.yaml | 15 +++++---- project/config/repeat_best/train.yaml | 15 +++++---- .../proteinGroups/train_CF.yaml | 1 - .../proteinGroups/train_DAE.yaml | 1 - .../proteinGroups/train_KNN.yaml | 3 +- .../proteinGroups/train_Median.yaml | 3 +- .../proteinGroups/train_VAE.yaml | 1 - project/workflow/Snakefile | 4 +-- .../Snakefile_best_repeated_split.smk | 2 ++ .../Snakefile_best_repeated_train.smk | 2 ++ 16 files changed, 73 insertions(+), 54 deletions(-) diff --git a/project/03_1_best_models_comparison.ipynb b/project/03_1_best_models_comparison.ipynb index 0a02134a1..6a6f6f6fe 100644 --- a/project/03_1_best_models_comparison.ipynb +++ b/project/03_1_best_models_comparison.ipynb @@ -21,7 +21,7 @@ "logger = setup_logger(logger=logging.getLogger('vaep'), level=10)\n", "\n", "plt.rcParams['figure.figsize'] = [4.0, 2.0]\n", - "vaep.plotting.make_large_descriptors(5)" + "vaep.plotting.make_large_descriptors(7)" ] }, { @@ -93,7 +93,10 @@ "min_max_MAE = (selected\n", " .loc[pd.IndexSlice[:, 'MAE', :]]\n", " .groupby('model')\n", - " .agg(['min', 'max']))\n", + " .agg(['min', 'max'])\n", + " .stack()\n", + " .T\n", + " .loc[IDX[0]])\n", "min_max_MAE.to_excel(writer, sheet_name='min_max_MAE')\n", "min_max_MAE" ] @@ -182,6 +185,16 @@ "vaep.savefig(fig, FOLDER / \"model_performance_repeated_runs.pdf\")" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "0813889a", + "metadata": {}, + "outputs": [], + "source": [ + "writer.close()" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/project/03_1_best_models_comparison.py b/project/03_1_best_models_comparison.py index 00bcb8ada..97c54d8b5 100644 --- a/project/03_1_best_models_comparison.py +++ b/project/03_1_best_models_comparison.py @@ -29,7 +29,7 @@ logger = setup_logger(logger=logging.getLogger('vaep'), level=10) plt.rcParams['figure.figsize'] = [4.0, 2.0] -vaep.plotting.make_large_descriptors(5) +vaep.plotting.make_large_descriptors(7) # %% IDX = [['proteinGroups', 'peptides', 'evidence'], @@ -63,7 +63,10 @@ min_max_MAE = (selected .loc[pd.IndexSlice[:, 'MAE', :]] .groupby('model') - .agg(['min', 'max'])) + .agg(['min', 'max']) + .stack() + .T + .loc[IDX[0]]) min_max_MAE.to_excel(writer, sheet_name='min_max_MAE') min_max_MAE @@ -114,3 +117,6 @@ vaep.savefig(fig, FOLDER / "model_performance_repeated_runs.pdf") # %% +writer.close() + +# %% diff --git a/project/config/knn_comparison/hela_pgs_large/config.yaml b/project/config/knn_comparison/hela_pgs_large/config.yaml index e618a31a3..671a9c222 100644 --- a/project/config/knn_comparison/hela_pgs_large/config.yaml +++ b/project/config/knn_comparison/hela_pgs_large/config.yaml @@ -2,23 +2,23 @@ config_split: config/knn_comparison/hela_pgs_large/split.yaml config_train: runs/knn_comparison/hela_pgs_large/configs_train/train_{model}.yaml folder_experiment: runs/knn_comparison/hela_pgs_large -fn_rawfile_metadata: data/dev_datasets/df_intensities_proteinGroups_long/metadata.csv +fn_rawfile_metadata: None file_format: csv cuda: False models: - - Median: - model: Median - - 3NN: - neighbors: 3 - model: KNN - - 5NN: - neighbors: 5 - model: KNN - - 10NN: - neighbors: 10 - model: KNN - - 15NN: - neighbors: 15 - model: KNN + - Median: + model: Median + - 3NN: + neighbors: 3 + model: KNN + - 5NN: + neighbors: 5 + model: KNN + - 10NN: + neighbors: 10 + model: KNN + - 15NN: + neighbors: 15 + model: KNN NAGuideR_methods: - - KNN_IMPUTE + - KNN_IMPUTE diff --git a/project/config/knn_comparison/hela_pgs_large/split.yaml b/project/config/knn_comparison/hela_pgs_large/split.yaml index 675f1b785..efb1f12d0 100644 --- a/project/config/knn_comparison/hela_pgs_large/split.yaml +++ b/project/config/knn_comparison/hela_pgs_large/split.yaml @@ -1,3 +1,3 @@ FN_INTENSITIES: data/dev_datasets/df_intensities_proteinGroups_long/Q_Exactive_HF_X_Orbitrap_6070.pkl sample_completeness: 0.5 -min_RT_time: 120 \ No newline at end of file +frac_mnar: 0.25 diff --git a/project/config/permuted_dataset/config.yaml b/project/config/permuted_dataset/config.yaml index 3d5657868..0b338744f 100644 --- a/project/config/permuted_dataset/config.yaml +++ b/project/config/permuted_dataset/config.yaml @@ -1,18 +1,16 @@ # config for Snakefile_v1 # fit permuted data to the same model as the original data -config_split: config/permuted_dataset/split.yaml # proteinGroups +config_split: config/permuted_dataset/split.yaml # proteinGroups config_train: config/single_dev_dataset/proteinGroups/train_{model}.yaml folder_experiment: runs/permuted #/proteinGroups fn_rawfile_metadata: # no metadata for permuted data cuda: False models: - - Median - - CF - - DAE - - VAE - - KNN + - Median + - CF + - DAE + - VAE + - KNN NAGuideR_methods: - - lls - - knnmethod - - rf - # - impseq # fails \ No newline at end of file + - KNN_IMPUTE + # - RF diff --git a/project/config/permuted_dataset/split.yaml b/project/config/permuted_dataset/split.yaml index 2bc14b229..69441fd23 100644 --- a/project/config/permuted_dataset/split.yaml +++ b/project/config/permuted_dataset/split.yaml @@ -1,2 +1,3 @@ FN_INTENSITIES: data/dev_datasets/df_intensities_proteinGroups_long/Q_Exactive_HF_X_Orbitrap_6070_permuted.pkl sample_completeness: 0.5 +frac_mnar: 0.25 diff --git a/project/config/repeat_best/split.yaml b/project/config/repeat_best/split.yaml index d47b203f9..766aa05c7 100644 --- a/project/config/repeat_best/split.yaml +++ b/project/config/repeat_best/split.yaml @@ -1,13 +1,14 @@ epochs_max: -- 100 + - 100 repeats: 5 folder: "runs/repeat_best_split" levels: -- proteinGroups -- peptides -- evidence + - proteinGroups + - peptides + - evidence fn_rawfile_metadata: data/dev_datasets/df_intensities_{level}_long/metadata.csv -config_split: 'config/single_dev_dataset/{level}/split.yaml' -config_train: 'config/single_dev_dataset/{level}/train_{model}.yaml' -repitition_name: 'repeat' +config_split: "config/single_dev_dataset/{level}/split.yaml" +config_train: "config/single_dev_dataset/{level}/train_{model}.yaml" +repitition_name: "repeat" file_format: pkl +cuda: True diff --git a/project/config/repeat_best/train.yaml b/project/config/repeat_best/train.yaml index b8cf4be09..976284b60 100644 --- a/project/config/repeat_best/train.yaml +++ b/project/config/repeat_best/train.yaml @@ -1,13 +1,14 @@ epochs_max: -- 100 + - 100 repeats: 5 folder: "runs/repeat_best_train" levels: -- proteinGroups -- peptides -- evidence + - proteinGroups + - peptides + - evidence fn_rawfile_metadata: data/dev_datasets/df_intensities_{level}_long/metadata.csv -config_split: 'config/single_dev_dataset/{level}/split.yaml' -config_train: 'config/single_dev_dataset/{level}/train_{model}.yaml' -repitition_name: 'repeat' +config_split: "config/single_dev_dataset/{level}/split.yaml" +config_train: "config/single_dev_dataset/{level}/train_{model}.yaml" +repitition_name: "repeat" file_format: pkl +cuda: True diff --git a/project/config/single_dev_dataset/proteinGroups/train_CF.yaml b/project/config/single_dev_dataset/proteinGroups/train_CF.yaml index 58370bd9c..2068cc158 100644 --- a/project/config/single_dev_dataset/proteinGroups/train_CF.yaml +++ b/project/config/single_dev_dataset/proteinGroups/train_CF.yaml @@ -1,5 +1,4 @@ file_format: csv -fn_rawfile_metadata: data/dev_datasets/df_intensities_proteinGroups_long/metadata.csv latent_dim: 50 batch_size: 32768 epochs_max: 100 diff --git a/project/config/single_dev_dataset/proteinGroups/train_DAE.yaml b/project/config/single_dev_dataset/proteinGroups/train_DAE.yaml index cab0c8246..b3a22c8bb 100644 --- a/project/config/single_dev_dataset/proteinGroups/train_DAE.yaml +++ b/project/config/single_dev_dataset/proteinGroups/train_DAE.yaml @@ -1,5 +1,4 @@ file_format: csv -fn_rawfile_metadata: data/dev_datasets/df_intensities_proteinGroups_long/metadata.csv latent_dim: 25 batch_size: 64 epochs_max: 100 diff --git a/project/config/single_dev_dataset/proteinGroups/train_KNN.yaml b/project/config/single_dev_dataset/proteinGroups/train_KNN.yaml index baa99b732..2d056f335 100644 --- a/project/config/single_dev_dataset/proteinGroups/train_KNN.yaml +++ b/project/config/single_dev_dataset/proteinGroups/train_KNN.yaml @@ -1,3 +1,2 @@ neighbors: 3 -file_format: csv -fn_rawfile_metadata: data/dev_datasets/df_intensities_proteinGroups_long/metadata.csv \ No newline at end of file +file_format: csv \ No newline at end of file diff --git a/project/config/single_dev_dataset/proteinGroups/train_Median.yaml b/project/config/single_dev_dataset/proteinGroups/train_Median.yaml index 340efcd69..745cca2c5 100644 --- a/project/config/single_dev_dataset/proteinGroups/train_Median.yaml +++ b/project/config/single_dev_dataset/proteinGroups/train_Median.yaml @@ -1,2 +1 @@ -file_format: csv -fn_rawfile_metadata: data/dev_datasets/df_intensities_proteinGroups_long/metadata.csv \ No newline at end of file +file_format: csv \ No newline at end of file diff --git a/project/config/single_dev_dataset/proteinGroups/train_VAE.yaml b/project/config/single_dev_dataset/proteinGroups/train_VAE.yaml index 2dc70a4ae..7caad9dab 100644 --- a/project/config/single_dev_dataset/proteinGroups/train_VAE.yaml +++ b/project/config/single_dev_dataset/proteinGroups/train_VAE.yaml @@ -1,6 +1,5 @@ # models_training: file_format: csv -fn_rawfile_metadata: data/dev_datasets/df_intensities_proteinGroups_long/metadata.csv latent_dim: 25 batch_size: 64 epochs_max: 50 diff --git a/project/workflow/Snakefile b/project/workflow/Snakefile index 5d44661ae..96b8e7a23 100644 --- a/project/workflow/Snakefile +++ b/project/workflow/Snakefile @@ -58,7 +58,7 @@ rule comparison: out=f"{{folder_experiment}}/{nb_stem}.o", shell: "papermill {input.nb} {output.nb:q}" - " -r fn_rawfile_metadata {params.meta_data:q}" + " -p fn_rawfile_metadata {params.meta_data:q}" " -r folder_experiment {wildcards.folder_experiment:q}" " -r models {params.models:q}" " && jupyter nbconvert --to html {output.nb:q}" @@ -179,7 +179,7 @@ rule train_models: "papermill {input.nb:q} {output.nb:q}" " -f {input.configfile:q}" " -r folder_experiment {params.folder_experiment:q}" - " -r fn_rawfile_metadata {params.meta_data:q}" + " -p fn_rawfile_metadata {params.meta_data:q}" " -r model_key {wildcards.model:q}" " 2> {log.err}" " && jupyter nbconvert --to html {output.nb:q}" diff --git a/project/workflow/Snakefile_best_repeated_split.smk b/project/workflow/Snakefile_best_repeated_split.smk index 279cc031f..b0c709114 100644 --- a/project/workflow/Snakefile_best_repeated_split.smk +++ b/project/workflow/Snakefile_best_repeated_split.smk @@ -97,6 +97,7 @@ rule train_models: model_key="{model}", meta_data=config["fn_rawfile_metadata"], file_format=config["file_format"], + cuda=config["cuda"], shell: "papermill {input.nb} {output.nb}" " -f {input.configfile}" @@ -104,4 +105,5 @@ rule train_models: " -r fn_rawfile_metadata {params.meta_data}" " -r file_format {params.file_format}" " -r model_key {params.model_key}" + " -p cuda {params.cuda}" " && jupyter nbconvert --to html {output.nb}" diff --git a/project/workflow/Snakefile_best_repeated_train.smk b/project/workflow/Snakefile_best_repeated_train.smk index a76c89351..2bbac4f86 100644 --- a/project/workflow/Snakefile_best_repeated_train.smk +++ b/project/workflow/Snakefile_best_repeated_train.smk @@ -91,6 +91,7 @@ rule train_models: model_key="{model}_{repeat}", meta_data=config["fn_rawfile_metadata"], file_format=config["file_format"], + cuda=config['cuda'], shell: "papermill {input.nb} {output.nb}" " -f {input.configfile}" @@ -98,4 +99,5 @@ rule train_models: " -r fn_rawfile_metadata {params.meta_data}" " -r file_format {params.file_format}" " -r model_key {params.model_key}" + " -p cuda {params.cuda}" " && jupyter nbconvert --to html {output.nb}" From 27d8ad2c0651604edc4921cf57ded095bb95659d Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 12 Dec 2023 16:46:48 +0100 Subject: [PATCH 69/70] :memo: add three newly added methods to overview --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d6f5f24a9..65782b91b 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,7 @@ Packages either are based on this repository, or were referenced by NAGuideR (Ta From the brief description in the table the exact procedure is not always clear. | Method | Package | source | status | name | -| ------------- | ----------------- | ------ | --- |------------------ | +| ------------- | ----------------- | ------ | ------ |------------------ | | CF | pimms | pip | | Collaborative Filtering | | DAE | pimms | pip | | Denoising Autoencoder | | VAE | pimms | pip | | Variational Autoencoder | @@ -206,7 +206,7 @@ From the brief description in the table the exact procedure is not always clear. | COLMEDIAN | e1071 | CRAN | | replace NA with column median | | ROWMEDIAN | e1071 | CRAN | | replace NA with row median | | KNN_IMPUTE | impute | BIOCONDUCTOR | | k nearest neighbor imputation | -| SEQKNN | SeqKnn | tar file | | Sequential k- nearest neighbor imputation
start with feature with least missing values and re-use imputed values for not yet imputed features +| SEQKNN | SeqKnn | tar file | | Sequential k- nearest neighbor imputation
starts with feature with least missing values and re-use imputed values for not yet imputed features | BPCA | pcaMethods | BIOCONDUCTOR | | Bayesian PCA missing value imputation | SVDMETHOD | pcaMethods | BIOCONDUCTOR | | replace NA initially with zero, use k most significant eigenvalues using Singular Value Decomposition for imputation until convergence | LLS | pcaMethods | BIOCONDUCTOR | | Local least squares imputation of a feature based on k most correlated features @@ -222,11 +222,12 @@ From the brief description in the table the exact procedure is not always clear. | TRKNN | - | script | | truncation k-nearest neighbor imputation | RF | missForest | CRAN | | Random Forest imputation (one feature at a time) | PI | - | - | | Downshifted normal distribution (per sample) +| GSIMP | - | script | | QRILC initialization and iterative Gibbs sampling with generalized linear models (glmnet) +| MSIMPUTE | msImpute | BIOCONDUCTOR | | Missing at random algorithm using low rank approximation +| MSIMPUTE_MNAR | msImpute | BIOCONDUCTOR | | Missing not at random algorithm using low rank approximation | ~~grr~~ | DreamAI | - | Fails to install | Rigde regression | ~~GMS~~ | GMSimpute | tar file | Fails on Windows | Lasso model - - ## Build status [![Documentation Status](https://readthedocs.org/projects/pimms/badge/?version=latest)](https://pimms.readthedocs.io/en/latest/?badge=latest) \ No newline at end of file From af85dd76c9e8327244552727aadc1e79dec113d4 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 12 Dec 2023 16:50:21 +0100 Subject: [PATCH 70/70] :bookmark: bump version to v.0.2.0 --- vaep/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vaep/__init__.py b/vaep/__init__.py index 7402b9bc1..20ad35526 100644 --- a/vaep/__init__.py +++ b/vaep/__init__.py @@ -23,7 +23,7 @@ savefig = vaep.plotting.savefig __license__ = 'GPLv3' -__version__ = (0, 1, 0) +__version__ = (0, 2, 0) # set some defaults