Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 6 additions & 34 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ jobs:
pre-commit:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.10", "3.11", "3.12"]
os: [ubuntu-latest]
python-version: ["3.10"]

runs-on: ${{ matrix.os }}

Expand All @@ -27,43 +27,15 @@ jobs:
python-version: ${{ matrix.python-version }}
check-latest: true

- name: Cache pip dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt', '**/requirements-dev.txt') }}
restore-keys: ${{ runner.os }}-pip-

- name: Install Python dependencies
- name: Install pre-commit
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
pip install torch
pip install torch_geometric
shell: bash

# - name: Install R
# uses: r-lib/actions/setup-r@v2
# with:
# r-version: "latest"

# - name: Install R packages
# run: |
# Rscript -e "if (!requireNamespace('BiocManager', quietly = TRUE)) install.packages('BiocManager', repos='https://cran.r-project.org')"
# Rscript -e "install.packages(c('dplyr', 'jsonlite'), repos='https://cran.r-project.org')"
# Rscript -e "BiocManager::install(c('impute', 'preprocessCore', 'GO.db', 'AnnotationDbi'), update=FALSE, ask=FALSE)"
# Rscript -e "install.packages('SmCCNet', repos='https://cran.r-project.org')"
# Rscript -e "install.packages('WGCNA', repos='https://cran.r-project.org')"
# shell: bash
pip install --upgrade pip
pip install pre-commit
pip install black flake8 mypy

- name: Cache pre-commit hooks
uses: actions/cache@v3
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }}
restore-keys: pre-commit-${{ runner.os }}-

- name: Run Pre-Commit Checks
if: matrix.os != 'ubuntu-latest'
run: pre-commit run --all-files --show-diff-on-failure
43 changes: 43 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Publish to PyPI and GitHub Packages

on:
push:
tags:
- "v*.*.*"

jobs:
build-and-publish:
runs-on: ubuntu-latest

steps:
- name: Check out code
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"

- name: Install build tools
run: |
python -m pip install --upgrade pip setuptools wheel twine

- name: Build source & wheel
run: |
python setup.py sdist bdist_wheel

- name: Publish to GitHub Packages
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
run: |
twine upload \
--repository-url https://upload.pypi.github.io/UCD-BDLab/BioNeuralNet \
dist/*

- name: Publish to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: |
twine upload dist/*
16 changes: 3 additions & 13 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ jobs:
pip install torch_geometric
shell: bash

- name: Run pytest
run: pytest tests/

# - name: Install R
# uses: r-lib/actions/setup-r@v2
# with:
Expand All @@ -54,16 +57,3 @@ jobs:
# Rscript -e "install.packages('SmCCNet', repos='https://cran.r-project.org')"
# Rscript -e "install.packages('WGCNA', repos='https://cran.r-project.org')"
# shell: bash

# - name: Run tests with pytest
# run: |
# find . -name ".coverage*" -delete
# pytest --cov=bioneuralnet --cov-report=xml tests/

# - name: Upload coverage to Codecov
# uses: codecov/codecov-action@v3
# with:
# token: ${{ secrets.CODECOV_TOKEN }}
# files: ./coverage.xml
# flags: unittests
# name: codecov-umbrella
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ doc_examples_outdated
dpmon_output
.enviroment
TCGA-BRCA_Dataset_testing*.ipynb

testsOLD
# Other example data and tests not needed in the repo.

Output**
Expand Down
12 changes: 6 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ repos:

- id: clean-coverage-files
name: Remove stale .coverage files
entry: bash -c "find . -name '.coverage*' -delete"
entry: bash -c "find . -name '.coverage*' -exec rm -f {} + 2>/dev/null || true"
language: system
stages: [pre-commit]

Expand All @@ -56,8 +56,8 @@ repos:
language: system
stages: [pre-commit]

# - id: run-tests
# name: Run Tests with Pytest
# entry: pytest --ignore=docs/source/examples --cov=bioneuralnet --cov-report=term-missing || true
# language: system
# types: [python]
- id: run-tests
name: Run Tests with Pytest
entry: bash -c "pytest tests"
language: system
types: [python]
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
- **Updated Tutorials and Documentation**: New end to end jupiter notebook example.
- **Updated Test**: All test have been updated and new ones have been added.

## [1.0.1] to [1.0.8] - 2025-04-24
## [1.0.1] to [1.0.9] - 2025-04-24

- **BUG**: A bug related to rdata files missing
- **New realease**: A new release will include documentation for the other updates. (1.1.0)
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# BioNeuralNet: Multi-Omics Integration with Graph Neural Networks
# BioNeuralNet: A Graph Neural Network based Multi-Omics Network Data Analysis Tool

[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/UCD-BDLab/BioNeuralNet/blob/main/LICENSE)
[![PyPI](https://img.shields.io/pypi/v/bioneuralnet)](https://pypi.org/project/bioneuralnet/)
Expand All @@ -8,7 +8,7 @@
[![Documentation](https://img.shields.io/badge/docs-read%20the%20docs-blue.svg)](https://bioneuralnet.readthedocs.io/en/latest/)


## Welcome to BioNeuralNet 1.0.8
## Welcome to BioNeuralNet 1.0.9

![BioNeuralNet Logo](assets/LOGO_WB.png)

Expand Down
2 changes: 1 addition & 1 deletion bioneuralnet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
- `datasets`: Contains example (synthetic) datasets for testing and demonstration purposes.
"""

__version__ = "1.0.8"
__version__ = "1.0.9"

from .network_embedding import GNNEmbedding
from .downstream_task import SubjectRepresentation
Expand Down
14 changes: 9 additions & 5 deletions bioneuralnet/downstream_task/subject_representation.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,17 @@ def __init__(
if omics_data is None or omics_data.empty:
raise ValueError("Omics data must be non-empty.")

if embeddings is None or embeddings.empty:
self.logger.info(
"No embeddings provided, please review documentation to see how to generate embeddings.")
if embeddings is None:
self.logger.warning("No embeddings provided, please review documentation to see how to generate embeddings.")
raise ValueError("Embeddings must be non-empty.")

if not isinstance(embeddings, pd.DataFrame):
raise ValueError("Embeddings must be provided as a pandas DataFrame.")

if embeddings.empty:
self.logger.warning("No embeddings provided, please review documentation to see how to generate embeddings.")
raise ValueError("Embeddings must be non-empty.")

if tune and phenotype_data is None:
raise ValueError("Phenotype data must be provided for classification-based tuning.")

Expand Down Expand Up @@ -260,6 +263,9 @@ def _integrate_embeddings(self, reduced: pd.DataFrame, method="multiply", alpha=

This is so at least 50% of the final output is influenced by the computed weight
"""
if not isinstance(reduced, (pd.DataFrame, pd.Series)):
raise ValueError("Reduced embeddings must be a pandas DataFrame or Series.")

missing_features = set(self.omics_data.columns) - set(reduced.index)
if missing_features:
self.logger.warning(f"Missing {len(missing_features)} features in reduced embeddings: {list(missing_features)[:5]}")
Expand All @@ -277,8 +283,6 @@ def _integrate_embeddings(self, reduced: pd.DataFrame, method="multiply", alpha=
weight_series = reduced.mean(axis=1)
elif isinstance(reduced, pd.Series):
weight_series = (reduced - reduced.min()) / (reduced.max() - reduced.min())
else:
raise ValueError("Reduced embeddings must be a pandas DataFrame or Series.")

weight_series = weight_series.fillna(0)
ranks = weight_series.rank(method="average")
Expand Down
3 changes: 2 additions & 1 deletion bioneuralnet/network_embedding/gnn_embedding.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ def __init__(
if omics_data.empty:
raise ValueError("Omics data cannot be empty.")
if clinical_data is not None and clinical_data.empty:
raise ValueError("Clinical data was provided but is empty.")
self.logger.warning("Clinical data was provided but is empty, setting to None.")
clinical_data = None

if adjacency_matrix.shape[0] != adjacency_matrix.shape[1]:
raise ValueError("Adjacency matrix must be square.")
Expand Down
23 changes: 17 additions & 6 deletions bioneuralnet/utils/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
from typing import Optional
import torch.nn.functional as F
from sklearn.covariance import GraphicalLasso
from .logger import get_logger

logger = get_logger(__name__)

def gen_similarity_graph(X:pd.DataFrame, k:int = 15, metric:str = "cosine", mutual:bool = False, per_node:bool = True, self_loops:bool = True) -> pd.DataFrame:
"""
Expand All @@ -30,6 +33,7 @@ def gen_similarity_graph(X:pd.DataFrame, k:int = 15, metric:str = "cosine", mutu
raise TypeError("X must be a pandas.DataFrame")

N = x_torch.size(0)
k = min(k, N-1)

# full similarity matrix
if metric == "cosine":
Expand Down Expand Up @@ -280,18 +284,25 @@ def gen_lasso_graph(X: pd.DataFrame, alpha: float = 0.01, self_loops: bool = Tru
"""
if isinstance(X, pd.DataFrame):
nodes = X.index
x_numpy = X.values
x_numpy = X.values.T
else:
raise TypeError("X must be a pandas.DataFrame")

model = GraphicalLasso(alpha=alpha, max_iter=200)
model.fit(x_numpy)
try:
model = GraphicalLasso(alpha=alpha, max_iter=1000)
model.fit(x_numpy)

P = torch.from_numpy(model.precision_).abs()
W = (P + P.t()) / 2

P = torch.from_numpy(model.precision_).abs()
W = (P + P.t()) / 2
except FloatingPointError:
logger.warning("Graphical Lasso failed to converge, using identity matrix instead.")
N = len(nodes)
W = torch.eye(N, dtype=torch.float32)

if self_loops:
W.fill_diagonal_(W.diagonal() + 1.0)
diag_indices = torch.arange(W.size(0), device=W.device)
W[diag_indices, diag_indices] += 1.0

W = F.normalize(W, p=1, dim=1)
final_graph = pd.DataFrame(W.cpu().numpy(), index=nodes, columns=nodes)
Expand Down
2 changes: 1 addition & 1 deletion docs/jupyter_execute/Quick_Start.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"BioNeuralNet version: 1.0.8\n"
"BioNeuralNet version: 1.0.9\n"
]
}
],
Expand Down
2 changes: 1 addition & 1 deletion docs/source/Quick_Start.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"BioNeuralNet version: 1.0.8\n"
"BioNeuralNet version: 1.0.9\n"
]
}
],
Expand Down
21 changes: 0 additions & 21 deletions docs/source/TCGA-BRCA_Dataset.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -60,27 +60,6 @@
"- [Direct Download BRCA](http://firebrowse.org/?cohort=BRCA&download_dialog=true)\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "60a6b53c",
"metadata": {},
"outputs": [],
"source": [
"# adjusting global pandas options for better display on web documentation\n",
"import pandas as pd\n",
"import warnings\n",
"import logging\n",
"\n",
"pd.set_option(\"display.max_columns\", 5)\n",
"pd.set_option(\"display.expand_frame_repr\", False)\n",
"warnings.filterwarnings(\"ignore\", category=UserWarning)\n",
"warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n",
"logging.getLogger(\"ray\").setLevel(logging.ERROR)\n",
"logging.getLogger(\"ray.tune\").setLevel(logging.ERROR)\n",
"logging.getLogger(\"torch_geometric\").setLevel(logging.ERROR)"
]
},
{
"cell_type": "markdown",
"id": "c9698b74",
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
try:
release = metadata.version("bioneuralnet")
except metadata.PackageNotFoundError:
release = "1.0.8"
release = "1.0.9"

project = "BioNeuralNet"
version = release
Expand Down
4 changes: 2 additions & 2 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
BioNeuralNet - Multi-Omics Integration with Graph Neural Networks
=================================================================
BioNeuralNet: A Graph Neural Network based Multi-Omics Network Data Analysis Tool
=================================================================================

.. image:: https://img.shields.io/badge/license-MIT-blue.svg
:target: https://github.com/UCD-BDLab/BioNeuralNet/blob/main/LICENSE
Expand Down
4 changes: 2 additions & 2 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ build

#others
ipywidgets
cptac
#cptac
dtt
tensorboardX
debugpy
PyYAML
node2vec
#node2vec
wheel
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = bioneuralnet
version = 1.0.8
version = 1.0.9
author = Vicente Ramos
author_email = vicente.ramos@ucdenver.edu
description = A comprehensive framework for integrating multi-omics data with neural network embeddings.
Expand Down
Loading