Skip to content

Commit 870cdb9

Browse files
authored
Merge pull request #205 from HelikarLab/remove-hardcoded-paths/proteomics
Remove hardcoded filepaths
2 parents 179c673 + c401696 commit 870cdb9

2 files changed

Lines changed: 106 additions & 176 deletions

File tree

main/como/proteomics_gen.py

Lines changed: 97 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import argparse
2-
import asyncio
1+
from __future__ import annotations
2+
3+
from pathlib import Path
34

45
import numpy as np
56
import pandas as pd
@@ -12,85 +13,71 @@
1213

1314

1415
# Load Proteomics
15-
def load_proteomics_data(datafilename, context_name):
16+
def process_proteomics_data(path: Path) -> pd.DataFrame:
1617
"""Load proteomics data from a given context and filename."""
17-
config = Config()
18-
data_path = config.data_dir / "data_matrices" / context_name / datafilename
19-
logger.info(f"Data Matrix Path: {data_path}")
20-
21-
if data_path.exists():
22-
proteomics_data = pd.read_csv(data_path, header=0)
23-
else:
24-
logger.error(f"Error: file not found: {data_path}")
25-
26-
return None
27-
2818
# Preprocess data, drop na, duplicate ';' in symbol,
29-
proteomics_data["gene_symbol"] = proteomics_data["gene_symbol"].astype(str)
30-
proteomics_data.dropna(subset=["gene_symbol"], inplace=True)
31-
pluralnames = proteomics_data[proteomics_data["gene_symbol"].str.contains(";") == True] # noqa: E712
32-
33-
for idx, row in pluralnames.iterrows():
34-
names = row["gene_symbol"].split(";")
35-
rows = []
19+
matrix: pd.DataFrame = pd.read_csv(path)
20+
if "gene_symbol" not in matrix.columns:
21+
raise ValueError("No gene_symbol column found in proteomics data.")
3622

37-
for name in names:
38-
rowcopy = row.copy()
39-
rowcopy["gene_symbol"] = name
40-
rows.append(rowcopy)
41-
proteomics_data.drop(index=idx, inplace=True)
42-
proteomics_data = pd.concat([proteomics_data, pd.DataFrame(rows)], ignore_index=True)
43-
44-
return proteomics_data
23+
matrix["gene_symbol"] = matrix["gene_symbol"].astype(str)
24+
matrix.dropna(subset=["gene_symbol"], inplace=True)
25+
matrix = matrix.assign(gene_symbol=matrix["gene_symbol"].str.split(";")).explode("gene_symbol")
26+
return matrix
4527

4628

4729
# read map to convert to entrez
48-
async def load_gene_symbol_map(gene_symbols: list[str]):
30+
async def load_gene_symbol_map(gene_symbols: list[str], entrez_map: Path | None = None):
4931
"""Add descirption...."""
50-
config = Config()
51-
filepath = config.data_dir / "proteomics_entrez_map.csv"
52-
if filepath.exists():
53-
df = pd.read_csv(filepath, index_col="gene_symbol")
32+
if entrez_map and entrez_map.exists():
33+
df = pd.read_csv(entrez_map, index_col="gene_symbol")
5434
else:
5535
biodbnet = BioDBNet()
5636
df = await biodbnet.async_db2db(
57-
values=gene_symbols, input_db=Input.GENE_SYMBOL, output_db=[Output.GENE_ID, Output.ENSEMBL_GENE_ID]
37+
values=gene_symbols,
38+
input_db=Input.GENE_SYMBOL,
39+
output_db=[Output.GENE_ID, Output.ENSEMBL_GENE_ID],
5840
)
5941
df.loc[df["gene_id"] == "-", ["gene_id"]] = np.nan
60-
df.to_csv(filepath, index_label="gene_symbol")
42+
df.to_csv(entrez_map, index_label="gene_symbol")
6143

6244
return df[~df.index.duplicated()]
6345

6446

65-
def abundance_to_bool_group(context_name, group_name, abundance_matrix, rep_ratio, hi_rep_ratio, quantile):
66-
"""Descrioption...."""
67-
config = Config()
68-
output_dir = config.result_dir / context_name / "proteomics"
69-
output_dir.mkdir(parents=True, exist_ok=True)
70-
71-
# write group abundances to individual files
72-
abundance_filepath = (
73-
config.result_dir / context_name / "proteomics" / "".join(["protein_abundance_", group_name, ".csv"])
74-
)
47+
def abundance_to_bool_group(
48+
context_name,
49+
abundance_filepath: Path,
50+
output_gaussian_img_filepath: Path,
51+
output_z_score_matrix_filepath: Path,
52+
abundance_matrix: pd.DataFrame,
53+
replicate_ratio: float,
54+
high_confidence_replicate_ratio: float,
55+
quantile: float,
56+
output_boolean_filepath: Path,
57+
):
58+
"""Convert proteomic data to boolean expression."""
7559
abundance_matrix.to_csv(abundance_filepath, index_label="entrez_gene_id")
76-
protein_transform_main(abundance_matrix, output_dir, group_name)
60+
protein_transform_main(
61+
abundance_df=abundance_matrix,
62+
output_gaussian_img_filepath=output_gaussian_img_filepath,
63+
output_z_score_matrix_filepath=output_z_score_matrix_filepath,
64+
)
7765

7866
# Logical Calculation
7967
abundance_matrix_nozero = abundance_matrix.replace(0, np.nan)
8068
thresholds = abundance_matrix_nozero.quantile(quantile, axis=0)
81-
testbool = pd.DataFrame(0, columns=list(abundance_matrix), index=abundance_matrix.index)
69+
testbool = pd.DataFrame(0, columns=abundance_matrix.columns, index=abundance_matrix.index)
8270

83-
for col in list(abundance_matrix):
71+
for col in abundance_matrix.columns:
8472
testbool.loc[abundance_matrix[col] > thresholds[col], [col]] = 1
8573

86-
abundance_matrix["pos"] = (abundance_matrix > 0).sum(axis=1) / abundance_matrix.count(axis=1)
8774
abundance_matrix["expressed"] = 0
88-
abundance_matrix.loc[(abundance_matrix["pos"] >= rep_ratio), ["expressed"]] = 1
8975
abundance_matrix["high"] = 0
90-
abundance_matrix.loc[(abundance_matrix["pos"] >= hi_rep_ratio), ["high"]] = 1
76+
abundance_matrix["pos"] = abundance_matrix[abundance_matrix > 0].sum(axis=1) / abundance_matrix.count(axis=1)
77+
abundance_matrix.loc[(abundance_matrix["pos"] >= replicate_ratio), ["expressed"]] = 1
78+
abundance_matrix.loc[(abundance_matrix["pos"] >= high_confidence_replicate_ratio), ["high"]] = 1
9179

92-
bool_filepath = output_dir / f"bool_prot_Matrix_{context_name}_{group_name}.csv"
93-
abundance_matrix.to_csv(bool_filepath, index_label="entrez_gene_id")
80+
abundance_matrix.to_csv(output_boolean_filepath, index_label="entrez_gene_id")
9481

9582

9683
def to_bool_context(context_name, group_ratio, hi_group_ratio, group_names):
@@ -156,129 +143,72 @@ def load_empty_dict():
156143

157144

158145
async def proteomics_gen(
159-
config_file: str,
160-
rep_ratio: float = 0.5,
161-
group_ratio: float = 0.5,
162-
hi_rep_ratio: float = 0.5,
163-
hi_group_ratio: float = 0.5,
146+
context_name: str,
147+
config_filepath: Path,
148+
matrix_filepath: Path,
149+
output_boolean_filepath: Path,
150+
output_gaussian_img_filepath: Path,
151+
output_z_score_matrix_filepath: Path,
152+
input_entrez_map: Path | None = None,
153+
replicate_ratio: float = 0.5,
154+
batch_ratio: float = 0.5,
155+
high_confidence_replicate_ratio: float = 0.7,
156+
high_confience_batch_ratio: float = 0.7,
164157
quantile: int = 25,
165158
):
166159
"""Generate proteomics data."""
167-
config = Config()
168-
if not config_file:
169-
raise ValueError("Config file must be provided")
160+
if not config_filepath.exists():
161+
raise FileNotFoundError(f"Config file not found at {config_filepath}")
162+
if config_filepath.suffix not in (".xlsx", ".xls"):
163+
raise FileNotFoundError(f"Config file must be an xlsx or xls file at {config_filepath}")
164+
165+
if not matrix_filepath.exists():
166+
raise FileNotFoundError(f"Matrix file not found at {matrix_filepath}")
167+
if matrix_filepath.suffix not in {".csv"}:
168+
raise FileNotFoundError(f"Matrix file must be a csv file at {matrix_filepath}")
170169

171170
if quantile < 0 or quantile > 100:
172171
raise ValueError("Quantile must be an integer from 0 to 100")
173172
quantile /= 100
174173

175-
prot_config_filepath = config.data_dir / "config_sheets" / config_file
176-
logger.info(f"Config file is at '{prot_config_filepath}'")
174+
config_df = pd.read_excel(config_filepath, sheet_name=context_name)
175+
matrix: pd.DataFrame = process_proteomics_data(matrix_filepath)
177176

178-
xl = pd.ExcelFile(prot_config_filepath)
179-
sheet_names = xl.sheet_names
177+
groups = config_df["group"].unique().tolist()
180178

181-
for context_name in sheet_names:
182-
datafilename = "".join(["protein_abundance_", context_name, ".csv"])
183-
config_sheet = pd.read_excel(prot_config_filepath, sheet_name=context_name)
184-
groups = config_sheet["group"].unique().tolist()
179+
for group in groups:
180+
indices = np.where([g == group for g in config_df["group"]])
181+
sample_columns = [*np.take(config_df["sample_name"].to_numpy(), indices).ravel().tolist(), "gene_symbol"]
182+
matrix = matrix.loc[:, sample_columns]
185183

186-
for group in groups:
187-
group_idx = np.where([g == group for g in config_sheet["group"].tolist()])
188-
cols = [*np.take(config_sheet["sample_name"].to_numpy(), group_idx).ravel().tolist(), "gene_symbol"]
189-
190-
proteomics_data = load_proteomics_data(datafilename, context_name)
191-
proteomics_data = proteomics_data.loc[:, cols]
192-
193-
symbols_to_ids = await load_gene_symbol_map(gene_symbols=proteomics_data["gene_symbol"].tolist())
194-
proteomics_data.dropna(subset=["gene_symbol"], inplace=True)
195-
if "uniprot" in proteomics_data.columns:
196-
proteomics_data.drop(columns=["uniprot"], inplace=True)
197-
198-
proteomics_data = proteomics_data.groupby(["gene_symbol"]).agg("max")
199-
proteomics_data["entrez_gene_id"] = symbols_to_ids["gene_id"]
200-
proteomics_data.dropna(subset=["entrez_gene_id"], inplace=True)
201-
proteomics_data.set_index("entrez_gene_id", inplace=True)
202-
203-
# save proteomics data by test
204-
abundance_to_bool_group(context_name, group, proteomics_data, rep_ratio, hi_rep_ratio, quantile)
205-
to_bool_context(context_name, group_ratio, hi_group_ratio, groups)
206-
207-
208-
def _main():
209-
parser = argparse.ArgumentParser(
210-
prog="proteomics_gen.py",
211-
description="Description goes here",
212-
epilog="For additional help, please post questions/issues in the MADRID GitHub repo at "
213-
"https://github.com/HelikarLab/MADRID or email babessell@gmail.com",
214-
)
215-
parser.add_argument(
216-
"-c",
217-
"--config-file",
218-
type=str,
219-
required=True,
220-
dest="config_file",
221-
help="The configuration file for proteomics",
222-
)
223-
parser.add_argument(
224-
"-r",
225-
"--replicate-ratio",
226-
type=float,
227-
required=False,
228-
default=0.5,
229-
dest="rep_ratio",
230-
help="Ratio of replicates required for a gene to be considered active in that group",
231-
)
232-
parser.add_argument(
233-
"-b",
234-
"--batch-ratio",
235-
type=float,
236-
required=False,
237-
default=0.5,
238-
dest="group_ratio",
239-
help="Ratio of groups (batches or studies) required for a gene to be considered active in a context",
240-
)
241-
parser.add_argument(
242-
"-hr",
243-
"--high-replicate-ratio",
244-
type=float,
245-
required=False,
246-
default=0.5,
247-
dest="hi_rep_ratio",
248-
help="Ratio of replicates required for a gene to be considered high-confidence in that group",
249-
)
250-
parser.add_argument(
251-
"-hb",
252-
"--high-batch-ratio",
253-
type=float,
254-
required=False,
255-
default=0.5,
256-
dest="hi_group_ratio",
257-
help="Ratio of groups (batches or studies) required for a gene to be considered high-confidence in a context",
258-
)
259-
260-
parser.add_argument(
261-
"-q",
262-
"--quantile",
263-
type=int,
264-
required=False,
265-
default=25,
266-
dest="quantile",
267-
help="The quantile of genes to accept. This should be an integer from 0% (no proteins pass) "
268-
"to 100% (all proteins pass).",
269-
)
270-
args = parser.parse_args()
271-
asyncio.run(
272-
proteomics_gen(
273-
args.config_file,
274-
args.rep_ratio,
275-
args.group_ratio,
276-
args.hi_rep_ratio,
277-
args.hi_group_ratio,
278-
args.quantile,
184+
symbols_to_gene_ids = await load_gene_symbol_map(
185+
gene_symbols=matrix["gene_symbol"].tolist(),
186+
entrez_map=input_entrez_map,
187+
)
188+
matrix.dropna(subset=["gene_symbol"], inplace=True)
189+
if "uniprot" in matrix.columns:
190+
matrix.drop(columns=["uniprot"], inplace=True)
191+
192+
matrix = matrix.groupby(["gene_symbol"]).agg("max")
193+
matrix["entrez_gene_id"] = symbols_to_gene_ids["gene_id"]
194+
matrix.dropna(subset=["entrez_gene_id"], inplace=True)
195+
matrix.set_index("entrez_gene_id", inplace=True)
196+
197+
# bool_filepath = output_dir / f"bool_prot_Matrix_{context_name}_{group_name}.csv"
198+
abundance_to_bool_group(
199+
context_name=context_name,
200+
abundance_filepath=matrix_filepath,
201+
abundance_matrix=matrix,
202+
replicate_ratio=replicate_ratio,
203+
high_confidence_replicate_ratio=high_confidence_replicate_ratio,
204+
quantile=quantile,
205+
output_boolean_filepath=output_boolean_filepath,
206+
output_gaussian_img_filepath=output_gaussian_img_filepath,
207+
output_z_score_matrix_filepath=output_z_score_matrix_filepath,
279208
)
209+
to_bool_context(
210+
context_name=context_name,
211+
group_ratio=batch_ratio,
212+
hi_group_ratio=high_confience_batch_ratio,
213+
group_names=groups,
280214
)
281-
282-
283-
if __name__ == "__main__":
284-
_main()

main/como/proteomics_preprocessing.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,23 +129,23 @@ def plot_gaussian_fit(z_results: ZResult, facet_titles: bool = True, x_min: int
129129

130130

131131
# Main function for protein abundance transformation
132-
def protein_transform_main(abundance_df: pd.DataFrame | str | Path, out_dir: str | Path, group_name: str) -> None:
132+
def protein_transform_main(
133+
abundance_df: pd.DataFrame | str | Path,
134+
output_gaussian_img_filepath: Path,
135+
output_z_score_matrix_filepath: Path,
136+
) -> None:
133137
"""Transform protein abundance data."""
134-
out_dir: Path = Path(out_dir)
135-
output_figure_directory = out_dir / "figures"
136-
output_figure_directory.mkdir(parents=True, exist_ok=True)
137-
138138
abundance_df: pd.DataFrame = (
139139
pd.read_csv(abundance_df) if isinstance(abundance_df, (str, Path)) else abundance_df.fillna(0)
140140
)
141141
abundance_df = abundance_df[np.isfinite(abundance_df).all(axis=1)] # Remove +/- infinity values
142142
z_transform: ZResult = z_score_calc(abundance_df, min_thresh=0)
143143

144144
fig = plot_gaussian_fit(z_results=z_transform, facet_titles=True, x_min=-4)
145-
fig.write_image(out_dir / "gaussian_fit.png")
146-
fig.write_html(out_dir / "gaussian_fit.html")
147-
logger.info(f"Wrote image to {out_dir / 'gaussian_fit.png'}")
145+
fig.write_image(output_gaussian_img_filepath.with_suffix(".png"))
146+
fig.write_html(output_gaussian_img_filepath.with_suffix(".html"))
147+
logger.info(f"Gaussian fit figure written to {output_gaussian_img_filepath}")
148148

149149
z_transformed_abundances = z_transform.zfpkm
150150
z_transformed_abundances[abundance_df == 0] = -4
151-
z_transformed_abundances.to_csv(out_dir / f"protein_zscore_Matrix_{group_name}.csv", index=False)
151+
z_transformed_abundances.to_csv(output_z_score_matrix_filepath, index=False)

0 commit comments

Comments
 (0)