Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a419777
better UI for preprocessing and postprocessing, added a panel layout …
Andrianarivelo Feb 12, 2026
98ade91
UI improvements for the post-processing tab, including a new "Save" b…
Andrianarivelo Feb 12, 2026
b52f65f
UI modification
Andrianarivelo Feb 12, 2026
9c86afa
improved gui performance by ensuring fullscreen is set after the wind…
Andrianarivelo Feb 12, 2026
5bb18ab
updated environment.yml to include pyqt5 and pyqtwebengine for better…
Andrianarivelo Feb 12, 2026
88d7158
new filtering method for panel layout, added a new function to analys…
Andrianarivelo Feb 12, 2026
eddb577
spatial map
Andrianarivelo Feb 19, 2026
5c4f238
improved spatial heatmaps
Andrianarivelo Feb 20, 2026
60ab368
compiled
Andrianarivelo Feb 26, 2026
aaa37c0
added .github/workflows/build-and-publish.yml
Andrianarivelo Feb 26, 2026
d9365e8
modifactions to .gitignore, panel_layout.json
Andrianarivelo Feb 26, 2026
e30561a
windows adjustments
Andrianarivelo Feb 27, 2026
196f84a
improved window focus handling in postprocessing tab
Andrianarivelo Feb 27, 2026
3622650
new GUI for postprocessing. Still needs work, but it's a start. Also …
Andrianarivelo Feb 27, 2026
13162e2
updated workflow to build and publish on push to main branch, updated…
Andrianarivelo Feb 27, 2026
f79b46f
better post-processing GUI layout, and added a "select all" checkbox …
Andrianarivelo Feb 27, 2026
41ce5df
new GUI and export functions, and some updates to the README and .git…
Andrianarivelo Mar 9, 2026
d66d1bc
export better
Andrianarivelo Mar 9, 2026
d8b25e4
fixed gitignore
Snapyou2 Mar 9, 2026
2017408
Merge branch 'Pyber_v0.15' of https://github.com/BelloneLab/pyBer int…
Snapyou2 Mar 9, 2026
4376626
Fixed gitignore
Snapyou2 Mar 9, 2026
5fc0aed
Performance improvements with dynamic downsampling + minor bugfixes
Snapyou2 Mar 9, 2026
bb4f91c
improved export of DIO channels to .csv, added option to export all c…
Andrianarivelo Mar 9, 2026
b943670
improved export functionality,
Andrianarivelo Mar 9, 2026
c716c5b
Merge branch 'Pyber_v0.15' of https://github.com/BelloneLab/pyBer int…
Andrianarivelo Mar 9, 2026
27ceaad
DIO export
Andrianarivelo Mar 10, 2026
1285d07
Untrack panel_layout.json as it is ignored
Snapyou2 Mar 10, 2026
57193bd
Added right click on box selection to cut/artifact/section it directly
Snapyou2 Mar 10, 2026
14a9298
Added multiple DIO/AOUT consolidation into a single file when exporting
Snapyou2 Mar 10, 2026
e201147
new UI for Pyber, including a new icon and a new color scheme. The UI…
Andrianarivelo Mar 12, 2026
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
187 changes: 187 additions & 0 deletions .github/workflows/build-and-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
name: Build and Publish

on:
push:
branches: [main, master, Pyber_v0.15]
tags: ["v*"]
pull_request:
branches: [main, master, Pyber_v0.15]
workflow_dispatch:

permissions:
contents: write

jobs:
build-windows:
runs-on: windows-latest
defaults:
run:
shell: bash -el {0}

steps:
- uses: actions/checkout@v4

- name: Set up Conda environment
uses: conda-incubator/setup-miniconda@v3
with:
activate-environment: pyBer
auto-activate-base: false
environment-file: environment.yml
channels: conda-forge
channel-priority: strict
use-mamba: true

- name: Show build environment
run: |
python --version
python -m pip --version
python -c "import os, sys; print('CONDA_PREFIX=', os.environ.get('CONDA_PREFIX')); print('PYTHON=', sys.executable)"

- name: Build Windows icon from assets
run: |
python -m pip install --upgrade pillow
mkdir -p build
python - <<'PY'
from pathlib import Path
from PIL import Image

src = Path("assets/pyBer_logo_big.png")
dst = Path("build/pyBer_logo_big.ico")
if not src.exists():
raise SystemExit(f"Missing icon source: {src}")

img = Image.open(src).convert("RGBA")
sizes = [(256, 256), (128, 128), (64, 64), (48, 48), (32, 32), (16, 16)]
img.save(dst, format="ICO", sizes=sizes)
print(f"Wrote {dst}")
PY

- name: Build with PyInstaller (last known good method)
run: |
BIN_DIR="$CONDA_PREFIX/Library/bin"
DLL_PATTERNS=(
"hdf5*.dll"
"zlib*.dll"
"blosc*.dll"
"libblosc2*.dll"
"libpng16*.dll"
"freetype*.dll"
"liblapack*.dll"
"libblas*.dll"
"libcblas*.dll"
"mkl_rt*.dll"
"mkl_core*.dll"
"mkl_intel_thread*.dll"
"mkl_intel_lp64*.dll"
"mkl_sequential*.dll"
"libmmd*.dll"
"libifcoremd*.dll"
"libifportmd*.dll"
"libiomp5md*.dll"
"libimalloc*.dll"
"svml_dispmd*.dll"
)

ADD_ARGS=()
declare -A SEEN_DLLS
shopt -s nullglob
for pattern in "${DLL_PATTERNS[@]}"; do
matches=("$BIN_DIR"/$pattern)
if [[ ${#matches[@]} -eq 0 ]]; then
echo "No matches for pattern: $pattern"
continue
fi
for dll_path in "${matches[@]}"; do
dll_name="$(basename "$dll_path")"
# Optional cluster/MPI BLACS DLLs are not required for local scipy use.
if [[ "$dll_name" =~ ^mkl_blacs_.*(intelmpi|msmpi).*\.dll$ ]]; then
echo "Skipping optional BLACS runtime: $dll_name"
continue
fi
if [[ -n "${SEEN_DLLS[$dll_name]:-}" ]]; then
continue
fi
echo "Bundling $dll_name"
ADD_ARGS+=(--add-binary "$dll_path;.")
SEEN_DLLS["$dll_name"]=1
done
done
shopt -u nullglob

python - <<'PY'
import numpy, scipy, h5py, sklearn
print("Import smoke test OK")
print("numpy:", numpy.__version__)
print("scipy:", scipy.__version__)
print("h5py:", h5py.__version__)
print("sklearn:", sklearn.__version__)
PY

python -m PyInstaller \
--noconfirm \
--clean \
--onefile \
--windowed \
--icon build/pyBer_logo_big.ico \
--add-data "assets;assets" \
--collect-binaries numpy \
--collect-binaries scipy \
--collect-binaries h5py \
--collect-binaries sklearn \
--exclude-module pyqtgraph.opengl \
--exclude-module OpenGL \
--name pyBer \
"${ADD_ARGS[@]}" \
pyBer/main.py

- name: Smoke test built EXE (switch to Postprocessing tab)
run: |
export PYBER_SMOKE_TEST=1
./dist/pyBer.exe

- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: pyber-windows-exe
path: dist/pyBer.exe
if-no-files-found: error

publish:
needs: [build-windows]
if: |
needs.build-windows.result == 'success' && (
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'push' &&
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/Pyber_v0.15' || startsWith(github.ref, 'refs/tags/'))
)
)
runs-on: ubuntu-latest
steps:
- name: Download Windows Artifact
uses: actions/download-artifact@v4
with:
name: pyber-windows-exe
path: ./publish

- name: Normalize Release Asset Name
run: |
set -euo pipefail
exe_path="$(find ./publish -type f -name '*.exe' | head -n 1 || true)"
if [[ -z "$exe_path" ]]; then
echo "No EXE found in downloaded artifact"
find ./publish -maxdepth 4 -type f -print || true
exit 1
fi
cp "$exe_path" ./publish/pyBer-windows.exe

- name: Create Release
uses: ncipollo/release-action@v1
with:
artifacts: "./publish/pyBer-windows.exe"
token: ${{ secrets.GITHUB_TOKEN }}
generateReleaseNotes: true
allowUpdates: true
tag: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || 'latest' }}
name: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || 'Latest Build' }}
prerelease: ${{ !startsWith(github.ref, 'refs/tags/') }}
27 changes: 27 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
pyBer.spec
build/pyBer/Analysis-00.toc
build/pyBer/base_library.zip
build/pyBer/EXE-00.toc
build/pyBer/PKG-00.toc
build/pyBer/pyBer.pkg
build/pyBer/PYZ-00.pyz
build/pyBer/PYZ-00.toc
build/pyBer/warn-pyBer.txt
build/pyBer/xref-pyBer.html
build/pyBer/localpycs/pyimod01_archive.pyc
build/pyBer/localpycs/pyimod02_importers.pyc
build/pyBer/localpycs/pyimod03_ctypes.pyc
build/pyBer/localpycs/pyimod04_pywin32.pyc
build/pyBer/localpycs/struct.pyc
dist/pyBer.exe
pyBer/__pycache__/gui_postprocessing.cpython-38.pyc
pyBer/__pycache__/gui_postprocessing.cpython-38.pyc
pyBer/__pycache__/gui_postprocessing.cpython-38.pyc
pyBer/__pycache__/gui_postprocessing.cpython-38.pyc
pyBer/__pycache__/gui_postprocessing.cpython-311.pyc
pyBer/__pycache__/main.cpython-311.pyc
pyBer/__pycache__/gui_postprocessing.cpython-311.pyc
pyBer/__pycache__/gui_postprocessing.cpython-38.pyc
pyBer/__pycache__/gui_postprocessing.cpython-311.pyc
pyBer/__pycache__
panel_layout.json
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,12 @@ The GUI exposes seven explicit output definitions:
- **Lasso**: sparse regression (requires `scikit-learn`)
- **RLM (HuberT)**: robust linear model via IRLS + Huber weighting (no extra dependency)

### Export
- Export processed output to:
- CSV (`time`, `output`, optional `dio`)
- HDF5 with raw, baseline, and metadata fields
- Drag-and-drop support for preprocessing and post-processing files.
### Export
- Export processed output to:
- CSV with configurable fields (`time` always included; raw/isobestic/output/DIO selectable)
- HDF5 with configurable raw/output/DIO/baseline datasets plus metadata
- Export field selection is saved and restored through the preprocessing configuration file.
- Drag-and-drop support for preprocessing and post-processing files.

---

Expand Down
Binary file added assets/pyBer.ico
Binary file not shown.
58 changes: 26 additions & 32 deletions environment.yml
Original file line number Diff line number Diff line change
@@ -1,37 +1,31 @@
name: pyBer
channels:
- conda-forge
- defaults

dependencies:
# Core interpreter
- python=3.11

# Numeric + signal processing
- numpy>=1.24
- scipy>=1.10
- pyqtgraph>=0.13
# File IO (Doric H5)
- h5py>=3.9

# Baseline correction
- pybaselines>=1.1

# GUI
- pyside6>=6.6


- scikit-learn>=1.3

# Quality-of-life / packaging
- pip
- setuptools
- wheel


- matplotlib>=3.8
name: pyBer
channels:
- conda-forge

dependencies:
# Core
- python=3.11

# Numeric and signal processing
- libblas=*=*openblas
- liblapack=*=*openblas
- libcblas=*=*openblas
- numpy>=1.24
- scipy>=1.10
- h5py>=3.9
- scikit-learn>=1.3
- pybaselines>=1.1
- pandas>=2.0
- openpyxl>=3.1

# GUI
- pyside6>=6.6
- pyqtgraph>=0.13
- matplotlib>=3.8

# Quality-of-life / packaging
- pip
- setuptools
- wheel
- pyinstaller>=6.0
- pyinstaller-hooks-contrib>=2024.0
28 changes: 28 additions & 0 deletions preprocessing_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"artifact_detection_enabled": true,
"artifact_overlay_visible": true,
"filtering_enabled": true,
"parameters": {
"artifact_detection_enabled": true,
"artifact_mode": "Adaptive MAD (windowed)",
"mad_k": 25.0,
"adaptive_window_s": 1.0,
"artifact_pad_s": 0.5,
"lowpass_hz": 2.1,
"filter_order": 1,
"target_fs_hz": 120.0,
"baseline_method": "arpls",
"baseline_lambda": 100000000000.0,
"baseline_diff_order": 2,
"baseline_max_iter": 50,
"baseline_tol": 0.001,
"asls_p": 0.01,
"output_mode": "zscore (motion corrected with fitted ref)",
"invert_polarity": false,
"reference_fit": "OLS (recommended)",
"lasso_alpha": 0.001,
"rlm_huber_t": 1.345,
"rlm_max_iter": 50,
"rlm_tol": 1e-06
}
}
Comment on lines +1 to +28
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preprocessing_config.json looks like a user-exported configuration snapshot (parameter values) rather than source. If it's only an example, consider moving it under an examples/ or assets/ directory and documenting it; otherwise it should not be committed to avoid shipping personal/project-specific defaults unintentionally.

Suggested change
{
"artifact_detection_enabled": true,
"artifact_overlay_visible": true,
"filtering_enabled": true,
"parameters": {
"artifact_detection_enabled": true,
"artifact_mode": "Adaptive MAD (windowed)",
"mad_k": 25.0,
"adaptive_window_s": 1.0,
"artifact_pad_s": 0.5,
"lowpass_hz": 2.1,
"filter_order": 1,
"target_fs_hz": 120.0,
"baseline_method": "arpls",
"baseline_lambda": 100000000000.0,
"baseline_diff_order": 2,
"baseline_max_iter": 50,
"baseline_tol": 0.001,
"asls_p": 0.01,
"output_mode": "zscore (motion corrected with fitted ref)",
"invert_polarity": false,
"reference_fit": "OLS (recommended)",
"lasso_alpha": 0.001,
"rlm_huber_t": 1.345,
"rlm_max_iter": 50,
"rlm_tol": 1e-06
}
}
{
"example_config": true,
"description": "Example preprocessing configuration template. For production or environment-specific use, supply a separate configuration file or override these values as needed.",
"artifact_detection_enabled": true,
"artifact_overlay_visible": true,
"filtering_enabled": true,
"parameters": {
"artifact_detection_enabled": true,
"artifact_mode": "Adaptive MAD (windowed)",
"mad_k": 25.0,
"adaptive_window_s": 1.0,
"artifact_pad_s": 0.5,
"lowpass_hz": 2.1,
"filter_order": 1,
"target_fs_hz": 120.0,
"baseline_method": "arpls",
"baseline_lambda": 100000000000.0,
"baseline_diff_order": 2,
"baseline_max_iter": 50,
"baseline_tol": 0.001,
"asls_p": 0.01,
"output_mode": "zscore (motion corrected with fitted ref)",
"invert_polarity": false,
"reference_fit": "OLS (recommended)",
"lasso_alpha": 0.001,
"rlm_huber_t": 1.345,
"rlm_max_iter": 50,
"rlm_tol": 1e-06
}
}

Copilot uses AI. Check for mistakes.
Binary file modified pyBer/__pycache__/analysis_core.cpython-311.pyc
Binary file not shown.
Binary file modified pyBer/__pycache__/analysis_core.cpython-38.pyc
Binary file not shown.
Binary file modified pyBer/__pycache__/gui_postprocessing.cpython-311.pyc
Binary file not shown.
Binary file modified pyBer/__pycache__/gui_postprocessing.cpython-38.pyc
Binary file not shown.
Binary file modified pyBer/__pycache__/gui_preprocessing.cpython-311.pyc
Binary file not shown.
Binary file modified pyBer/__pycache__/gui_preprocessing.cpython-38.pyc
Binary file not shown.
Binary file modified pyBer/__pycache__/main.cpython-311.pyc
Binary file not shown.
Binary file modified pyBer/__pycache__/styles.cpython-311.pyc
Binary file not shown.
Binary file modified pyBer/__pycache__/styles.cpython-38.pyc
Binary file not shown.
Loading
Loading