Skip to content

Commit

Permalink
Merge pull request #17 from singjc/main
Browse files Browse the repository at this point in the history
Add: gh actions
  • Loading branch information
singjc authored Aug 7, 2024
2 parents 6fe4712 + e15d3ac commit 2529388
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 28 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Upload Python Package

on:
release:
types: [published]

permissions:
contents: read

jobs:
deploy:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
26 changes: 26 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Create a new patch release

on: [workflow_dispatch]

jobs:
resources:
name: Update __init__.py patch version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
- name: Update version
run: |
pwd
$PWD/.github/workflows/scripts/update_init_version.py --file-path $PWD/pyopenms_viz/__init__.py
- name: Commit version update
uses: test-room-7/action-update-file@v1
with:
file-path: pyopenms_viz/__init__.py
commit-msg: Bump patch version
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v3
- name: Create new patch release
run: $PWD/.github/workflows/scripts/release.py
env:
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
48 changes: 48 additions & 0 deletions .github/workflows/scripts/release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
import json
import subprocess


def get_last_version() -> str:
"""Return the version number of the last release."""
json_string = (
subprocess.run(
["gh", "release", "view", "--json", "tagName"],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
.stdout.decode("utf8")
.strip()
)

return json.loads(json_string)["tagName"]


def bump_patch_number(version_number: str) -> str:
"""Return a copy of `version_number` with the patch number incremented."""
major, minor, patch = version_number.split(".")
return f"{major}.{minor}.{int(patch) + 1}"


def create_new_patch_release():
"""Create a new patch release on GitHub."""
try:
last_version_number = get_last_version()
except subprocess.CalledProcessError as err:
if err.stderr.decode("utf8").startswith("HTTP 404:"):
# The project doesn't have any releases yet.
new_version_number = "0.0.1"
else:
raise
else:
new_version_number = bump_patch_number(last_version_number)

subprocess.run(
["gh", "release", "create", "--generate-notes", new_version_number],
check=True,
)


if __name__ == "__main__":
create_new_patch_release()
53 changes: 53 additions & 0 deletions .github/workflows/scripts/update_init_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
import re
import argparse

def update_version(init_file_path, version_type='patch'):
print(f"Updating {version_type} version in {init_file_path}...")
with open(init_file_path, 'r') as file:
init_content = file.read()

# Use a regular expression to find and extract the current version
version_match = re.search(r"__version__ = \"(.*?)\"", init_content)
if version_match:
current_version = version_match.group(1)
print(f"Current version: {current_version}")

# Increment the version based on the specified version type
version_parts = list(map(int, current_version.split('.')))
if version_type == 'major':
version_parts[0] += 1
version_parts[1] = 0 # Reset minor version to 0
version_parts[2] = 0 # Reset patch version to 0
elif version_type == 'minor':
version_parts[1] += 1
version_parts[2] = 0 # Reset patch version to 0
elif version_type == 'patch':
version_parts[2] += 1
else:
print("Invalid version type. Please use 'major', 'minor', or 'patch'.")
return

new_version = '.'.join(map(str, version_parts))
print(f"New version: {new_version}")

# Replace the version in the content
updated_content = re.sub(r"(__version__ = \")(.*?)(\")", rf"\g<1>{new_version}\g<3>", init_content)

print(f"Updating {init_file_path}:\n{updated_content}...")
# Write the updated content back to the file
with open(init_file_path, 'w') as file:
file.write(updated_content)

print("Version updated successfully.")
else:
print("Could not find the version in the init file.")

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Update the version in the __init__.py file.")
parser.add_argument("--file-path", default='__init__.py', help="Path to the __init__.py file")
parser.add_argument("--version-type", choices=['major', 'minor', 'patch'], default='patch',
help="Type of version update (default: patch)")

args = parser.parse_args()
update_version(args.file_path, args.version_type)
66 changes: 38 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
This repository holds the interactive visualization library for PyOpenMS.


Organization
_core.py:
1. BasePlotter: Abstract BaseClass which all PyOpenMSViz objects are derived from
- Defines methods that must be implemented by the backends
- Initiates objects and does common error checking - checking was previously done in `PlannarPlot()` class has been moved here
3. LinePlot, ScatterPlot etc. Simple Plots, plot method is defined in the specific modules
4. ComplexPlot: Abstract class which contains one or more simple plots
- ChromatogramPlot, MobilogramPlot, PeakMapPlot, SpectrumPlot all inherit from this
- Contains methods that generate a simple plot object
- For the most part, complex plots should allow plotting independent from each backend, should be able to construct the plots with commonly defined pyopenmsViz methods defined in the BasePlotter
5. ChromatogramPlot, SpectrumPlot, PeakMapPlot: Complex plots. Must have a plot() function defined in general their plot methods should only consist of common functions defined in BasePlotter

core.py
All backends follow the same structure, as an example look at _bokeh/core.py
1. BOKEHPlot: Inherits from BasePlotter, implements abstract methods using bokeh
2. BOKEHLinePlot, BOKEHVLinePlot, BOKEHScattePlot - simple plots, plotting methods rely heavily on BOKEH specifics. Inherit from BOKEHPlot and the base simple plot classes (e.g. LinePlot, VLinePlot etc.)
3. BOKEHComplexPlot: Inherits from ComplexPlot and BOKEHPlot, provides framework for complex plots using bokeh

4. BOKEHChromatogramPlot: Inherits from BOKEHComplexPlot and ChromatogramPlot. Defines bokeh specific methods for chromatogram. The plot() method from the parent ChromatogramPlot class does not have to be redefined
- Some plots and some backends have to supplement the plot() method but in most cases it does not have to be changed dramatically from the base _core.py
- MobilogramPlot, SpectrumPlot etc all follow a similar format.

See jupyter notebooks for examples of how to use the different plotters.

To run the demo streamlit app, run `streamlit run app.py` in the root directory of this repository.
# Python Pandas-Based OpenMS Visualization Library

pyopenms_viz is a Python library that provides a simple interface for extending the plotting capabilities of Pandas DataFrames for creating static or interactive visualizations of mass spectrometry data. It integrates seamlessly with various plotting library backends (matpotlib, bokeh and plotly) and leverages the power of Pandas for data manipulation and representation.

## Features

- Flexible plotting API that interfaces directly with Pandas DataFrames
- Support for multiple plotting backends: matplotlib (static), bokeh and plotly (interactive)
- Visualization of various mass spectrometry data types, including 1D chromatograms, spectra, and 2D peak maps
- Versatile column selection for easy adaptation to different data formats
- Consistent API across different plotting backends for easy switching between static and interactive plots
- Suitable for use in scripts, Jupyter notebooks, and web applications

## (Recommended) Pip Installation

The recommended way of installing pyopenms_viz is through the Python Package Index (PyPI). We recommend installing pyopenms_viz in its own virtual environment using Anaconda to avoid packaging conflicts.

First create a new environemnt:

```bash
conda create --name=massdash python=3.10
conda activate pyopenms_viz
```
Then in the new environment install pyopenms_viz.

```bash
pip install pyopenms_viz --upgrade
```

## Documentation

Documentation (*work in progress*).

## References

- Pfeuffer, J., Bielow, C., Wein, S. et al. OpenMS 3 enables reproducible analysis of large-scale mass spectrometry data. Nat Methods 21, 365–367 (2024). [https://doi.org/10.1038/s41592-024-02197-7](https://doi.org/10.1038/s41592-024-02197-7)

- Röst HL, Schmitt U, Aebersold R, Malmström L. pyOpenMS: a Python-based interface to the OpenMS mass-spectrometry algorithm library. Proteomics. 2014 Jan;14(1):74-7. [https://doi.org/10.1002/pmic.201300246](https://doi.org/10.1002/pmic.201300246). PMID: [24420968](https://pubmed.ncbi.nlm.nih.gov/24420968/).

0 comments on commit 2529388

Please sign in to comment.