5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 |
3 | # Doctoc generates the table of contents for each markdown file.
4 | - repo: https://github.com/thlorenz/doctoc
5 | rev: v1.4.0
6 | hooks:
7 | - id: doctoc
8 | args: ["docs", # Apply to everything inside the 'docs' folder.
9 | '--title=## Table of Contents', # Set the title of the table of contents.
10 | "--maxlevel=2", # Only add sections with `#` or `##`.
11 | "--github"] # Use GitHub formatting.
12 |
13 | # Black formats Python files.
14 | - repo: https://github.com/ambv/black
15 | rev: stable
16 | hooks:
17 | - id: black
18 | language_version: python3
19 | files: ^src/ # Include all files within `src/`.
20 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Only build tagged releases on the master branch.
2 | if:
3 | - tag IS present
4 | - branch = master
5 |
6 | language: generic
7 | cache:
8 | directories:
9 | - /Library/Caches/Homebrew
10 | - $HOME/.cache/pip
11 |
12 | matrix:
13 | include:
14 | - dist: bionic
15 | - os: osx
16 |
17 | install:
18 | - if [ "$TRAVIS_OS_NAME" == "osx" ] ; then sudo chmod +x build/macos/build.sh && build/macos/build.sh ; fi
19 | - if [ "$TRAVIS_OS_NAME" == "linux" ] ; then sudo chmod +x build/linux/build.sh && build/linux/build.sh ; fi
20 |
21 | script: true
22 |
23 | deploy:
24 | provider: releases
25 | api_key:
26 | secure: NzRG8BAjBQCfzCB7DqyEI/KuH/NQGtRnlywgqf1cvaVwPG5itr0Uo9X7sAc2oeIqTpV/7CMQxzqdS+3ujRCyXx9rMQKIMEjEeZU9uLO4QX5AL2JXCac10HB0PXulREa1mMExr9kOGSLs35JQEYCpzdOyesyZGSHTYWjJpuk9/ryyzKSzzJgH99quzGlsguampXX2v8tTpjT49oURFKcF/ra3iWh1ueg+zKgHPaJq5ZNzMFrG2MaAQALAii0AqaXNhsLr3tfCzcHPxxTrCgBxBGk0vSCtGkLOjNCL4GOXTe4wEedeSCjzeJw0eYO7ojM7Zv8bS7whhSeXTgjlKXngcb54+xDpHb/iByesGZwy6M+4Zd+IejjRw5LN5OuBSf/dCSHZ/DYrqdoWFe6cKdWGiRU9VQzCdLFs5vCUZLBjmfaDi1KqKmruV12K9UBDiTXAzXAQG48J2Bv3xXpjrBvBiFXW8O+ddnrlNufsWTmJyV/sLFjnQhWh+FBsByz5es4Zv6whnxSIVLkFJYZZ07RNHKF3AQjphsHU8V/buhuph7FSFsPzejujQOM41QDTpigN1prSyqFEqv+jaM11bEsPujP2JhuWUruSZpDmb/IDrvNXZPT1r7ydtGXiP5qLCEDJy+9xUwrL+guoyCXYDyVxJTD87kzrmTx03aw5e6/o9/M=
27 | file_glob: true
28 | file: 'releases/PyMODA*'
29 | on:
30 | repo: luphysics/PyMODA
31 | tags: true
32 | skip_cleanup: 'true'
33 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | skip_non_tags: true
2 |
3 | image: Visual Studio 2019
4 |
5 | environment:
6 | PYTHON: "C:\\PYTHON37-x64"
7 |
8 | install:
9 | - "%PYTHON%\\python.exe -m pip install -U pip --user"
10 |
11 | build_script:
12 | - cmd: cmd /c build\windows\build.bat
13 |
14 | artifacts:
15 | - path: releases/PyMODA-win64.zip
16 | name: portable
17 |
18 | deploy:
19 | - provider: GitHub
20 | tag: $(APPVEYOR_REPO_TAG_NAME)
21 | description: "Release $(APPVEYOR_REPO_TAG_NAME)"
22 | auth_token:
23 | secure: z8OqFPVcisBMWLDG/O/XsyqQaUgGgi4F4L3sMxQxk80JQm2IKmwQZC+fcbMd+RjZ
24 | draft: false
25 | prerelease: false
26 | force_update: true
27 | artifact: portable
28 | on:
29 | APPVEYOR_REPO_TAG: true
30 |
--------------------------------------------------------------------------------
/build/.resignore:
--------------------------------------------------------------------------------
1 | # This file defines files and folders which will be deleted
2 | # when 'strip_resources.py' is executed. This reduces the size
3 | # of the packaged executable.
4 | #
5 | # Paths listed here are relative to the 'res' directory.
6 | #
7 | # Note: This file uses only simplified syntax.
8 | # Each value must be a Unix-style pathname pattern.
9 |
10 | data/npy
11 |
12 | butter.mat
13 | xp_100Hz.mat
14 | freq_mod_200Hz.mat
15 |
16 | load_*.mat
17 | noisyyy.mat
18 |
19 | heartrate.csv
20 | ECG.csv
21 | ecgtest.csv
--------------------------------------------------------------------------------
/build/linux/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | sudo add-apt-repository ppa:deadsnakes/ppa -y
5 |
6 | sudo apt-get update
7 | sudo apt-get install python3.7 python3.7-dev -y
8 | sudo apt-get install python3-pip -y
9 |
10 | python3.7 --version
11 |
12 | python3.7 -m pip install -U pip
13 | python3.7 -m pip install -U setuptools wheel
14 | python3.7 -m pip install -U PyInstaller
15 |
16 | python3.7 packages/install.py -y
17 | python3.7 -m pip install -U Pillow
18 |
19 | python3.7 build/strip_resources.py -y
20 | python3.7 -m PyInstaller main.spec --noconfirm
21 |
22 | cd dist
23 | mv main PyMODA
24 |
25 | tar -zcf PyMODA-linux_x86_64.tar.gz PyMODA
26 | cd ..
27 |
28 | mkdir -p releases
29 | mv dist/PyMODA-linux_x86_64.tar.gz releases/
--------------------------------------------------------------------------------
/build/macos/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | python3 --version
5 |
6 | python3 -m pip install -U pip
7 | python3 -m pip install PyInstaller
8 |
9 | python3 packages/install.py -yv
10 | python3 build/strip_resources.py -y
11 |
12 | python3 -m PyInstaller macos.spec --noconfirm
13 |
14 | mv dist/PyMODA.app .
15 |
16 | tar -zcf PyMODA-macOS.tar.gz PyMODA.app
17 |
18 | mkdir -p releases
19 | mv PyMODA-macOS.tar.gz releases/
20 |
--------------------------------------------------------------------------------
/build/strip_resources.py:
--------------------------------------------------------------------------------
1 | """
2 | Script which deletes unwanted resources in the 'res' folder to reduce the size
3 | of the packaged executable.
4 | """
5 | import os
6 | from os.path import join
7 | from pathlib import Path
8 | import sys
9 | import shutil
10 | from typing import List
11 |
12 | args = sys.argv[1:]
13 | delete = "-y" in args
14 |
15 | if not delete:
16 | print(
17 | "Please note, files will not actually be "
18 | "deleted unless the '-y' argument is used.",
19 | end="\n\n"
20 | )
21 |
22 | wd = str(Path(os.path.abspath(os.path.dirname(__file__))).parent)
23 | assert wd == os.getcwd(), "Working directory must be the root of the repository."
24 |
25 | build_dir = os.path.abspath(os.path.dirname(__file__))
26 | wd = os.getcwd()
27 | res_dir = join(wd, "res")
28 |
29 |
30 | def load_ignores() -> List[str]:
31 | out = []
32 |
33 | with open(join(build_dir, ".resignore")) as f:
34 | for line in f:
35 | if not line.startswith("#"):
36 | out.append(line.rstrip("\n"))
37 |
38 | return [i for i in out if i]
39 |
40 |
41 | ignores = load_ignores()
42 |
43 | for pattern in ignores:
44 | for f in Path(res_dir).rglob(f"{pattern}"):
45 | print(f"Deleting resource: '{f}'")
46 |
47 | if delete:
48 | try:
49 | os.remove(f)
50 | except:
51 | shutil.rmtree(f)
52 |
--------------------------------------------------------------------------------
/build/windows/build.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | "%PYTHON%\python.exe" -m pip install -U setuptools wheel
4 | "%PYTHON%\python.exe" -m pip install -U PyInstaller
5 |
6 | "%PYTHON%\python.exe" packages\install.py -y
7 | "%PYTHON%\python.exe" build\strip_resources.py -y
8 |
9 | "%PYTHON%\python.exe" -m PyInstaller main.spec --noconfirm
10 |
11 | cd dist
12 | move main PyMODA
13 |
14 | 7z a -r PyMODA-win64.zip PyMODA
15 | cd ..
16 |
17 | mkdir releases
18 | move dist\PyMODA-win64.zip releases\
--------------------------------------------------------------------------------
/dist/linux/install.sh:
--------------------------------------------------------------------------------
1 | echo "Downloading PyMODA. Please wait, this may take over a minute..."
2 | curl -fsSL "https://github.com/luphysics/PyMODA/releases/latest/download/PyMODA-linux_x86_64.tar.gz" -o pymoda.tar.gz
3 |
4 | echo "Extracting PyMODA..."
5 | mkdir -p ~/.pymoda
6 | tar -xf pymoda.tar.gz -C ~/.pymoda/
7 |
8 | echo "Cleaning up..."
9 | rm pymoda.tar.gz
10 |
11 | echo "Launching PyMODA..."
12 | ~/.pymoda/PyMODA/PyMODA
13 |
--------------------------------------------------------------------------------
/dist/windows/install.ps1:
--------------------------------------------------------------------------------
1 | # Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/luphysics/PyMODA/dev/dist/windows/install.ps1'))
2 |
3 | Write-Output "Downloading PyMODA. Please wait, this may take over a minute..."
4 |
5 | $url = "https://github.com/luphysics/PyMODA/releases/latest/download/PyMODA-win64.zip"
6 |
7 | $targetDir = "$env:AppData\PyMODA"
8 | $targetFile = "$targetDir\pymoda.zip"
9 |
10 | ### Download the .zip file ###
11 |
12 | $uri = New-Object "System.Uri" "$url"
13 |
14 | $request = [System.Net.HttpWebRequest]::Create($uri)
15 | $request.set_Timeout(15000)
16 | $response = $request.GetResponse()
17 |
18 | $totalLength = [System.Math]::Floor($response.get_ContentLength()/1024)
19 | $responseStream = $response.GetResponseStream()
20 | $targetStream = New-Object -TypeName System.IO.FileStream -ArgumentList $targetFile, Create
21 |
22 | $buffer = new-object byte[] 10KB
23 | $count = $responseStream.Read($buffer,0,$buffer.length)
24 | $downloadedBytes = $count
25 |
26 | while ($count -gt 0)
27 | {
28 | $targetStream.Write($buffer, 0, $count)
29 | $count = $responseStream.Read($buffer,0,$buffer.length)
30 | $downloadedBytes = $downloadedBytes + $count
31 | Write-Progress -activity "Downloading file '$($url.split('/') | Select -Last 1)'" -status "Downloaded ($([System.Math]::Floor($downloadedBytes/1024))K of $($totalLength)K): " -PercentComplete ((([System.Math]::Floor($downloadedBytes/1024)) / $totalLength) * 100)
32 | }
33 |
34 | Write-Progress -activity "Finished downloading file '$($url.split('/') | Select -Last 1)'"
35 |
36 | $targetStream.Flush()
37 | $targetStream.Close()
38 | $targetStream.Dispose()
39 | $responseStream.Dispose()
40 |
41 | ### Extract the .zip file ###
42 |
43 | Write-Output "Extracting PyMODA..."
44 |
45 | mkdir -Force "$targetDir\PyMODA"
46 | rm -r "$targetDir\PyMODA"
47 |
48 | Add-Type -AssemblyName System.IO.Compression.FileSystem
49 | [System.IO.Compression.ZipFile]::ExtractToDirectory($targetFile, $targetDir)
50 |
51 | Write-Output "Cleaning up..."
52 | rm $targetFile
53 |
54 | Write-Output "Launching PyMODA..."
55 | & "$targetDir\PyMODA\PyMODA.exe" --create-shortcut
--------------------------------------------------------------------------------
/docs/images/TFPresenter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/docs/images/TFPresenter.png
--------------------------------------------------------------------------------
/docs/images/git_hooks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/docs/images/git_hooks.png
--------------------------------------------------------------------------------
/docs/images/scheduler.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/docs/images/scheduler.png
--------------------------------------------------------------------------------
/docs/images/update_available.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/docs/images/update_available.png
--------------------------------------------------------------------------------
/docs/performance.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Table of Contents
4 |
5 | - [Performance and efficiency](#performance-and-efficiency)
6 | - [Concurrency](#concurrency)
7 | - [Windows vs Linux](#windows-vs-linux)
8 |
9 |
10 |
11 | # Performance and efficiency
12 |
13 | ## Concurrency
14 |
15 | When performing multiple discrete calculations - for example, the wavelet transform of 6 signals - PyMODA uses multiprocessing to greatly increase efficiency by allocating different calculations to different CPU cores.
16 |
17 | Therefore, it is more efficient to transform multiple signals if possible. Efficiency will plateau when the number of signals is higher than the number of CPU cores.
18 |
19 | ### AMD Ryzen 3700X
20 |
21 | The AMD Ryzen 3700X is an 8-core, 16-thread CPU. These tests were run on Manjaro Linux.
22 |
23 | | Operation | Total time: individually ("Transform Single" for all) | Total time: simultaneously ("Transform All") | Performance improvement |
24 | | ------------- | ------------- | ------ | ------ |
25 | | WT on 32 signals | 134s | 19.1s | x7.0 |
26 |
27 | ### Intel i7-6700
28 |
29 | The Intel i7-6700 is a 4-core, 8-thread CPU. These tests were run on KDE neon.
30 |
31 | | Operation | Total time: individually ("Transform Single" for all) | Total time: simultaneously ("Transform All") | Performance improvement |
32 | | ------------- | ------------- | ------ | ------ |
33 | | WT on 2 signals | 10s | 5.4s | x1.9 |
34 | | WT on 6 signals | 30s | 8.4s | x3.6 |
35 | | WT on 32 signals | 160s | 43.1s | x3.7 |
36 |
37 | ## Windows vs Linux
38 |
39 | Linux performs slightly better than Windows with a small number of signals, and significantly better with many signals.
40 |
41 | ### AMD Ryzen 3700X
42 |
43 | | Operating system | Time: WT on 1 signal | Time: WT on 32 signals |
44 | | ---- | ---- | ---- |
45 | | Windows 10 | 4.7s | 33.1s |
46 | | Manjaro Linux | 4.2s | 19.1s |
47 |
48 | ### Intel i7-6700
49 |
50 | | Operating system | Time: WT on 6 signals | Time: WT on 32 signals |
51 | | ---- | ---- | ---- |
52 | | Windows 10 (VM) | 17.5s | 82s |
53 | | Manjaro Linux (VM) | 17.4s | 74s |
54 |
--------------------------------------------------------------------------------
/macos.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python ; coding: utf-8 -*-
2 |
3 | block_cipher = None
4 |
5 | import os
6 | import os.path
7 |
8 | def find_packages():
9 | from pathlib import Path
10 |
11 | out = []
12 |
13 | for f in Path(".").rglob("**/for_redistribution_files_only/*"):
14 | head, tail = os.path.split(f)
15 |
16 | if os.path.isdir(f) and tail.lower() in head.lower():
17 | out.append((f, tail,))
18 |
19 | return out
20 |
21 |
22 | data = [
23 | ("res", "res"),
24 | ("LICENSE", "."),
25 | *find_packages(),
26 | ]
27 |
28 | a = Analysis(
29 | ["src/main.py"],
30 | pathex=[os.getcwd()],
31 | binaries=[],
32 | datas=data,
33 | hiddenimports=[
34 | "qasync",
35 | "gui.dialogs.files.DragDropLabel",
36 | ],
37 | hookspath=[],
38 | runtime_hooks=[],
39 | excludes=[],
40 | win_no_prefer_redirects=False,
41 | win_private_assemblies=False,
42 | cipher=block_cipher,
43 | noarchive=False,
44 | )
45 |
46 | pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
47 |
48 | exe = EXE(
49 | pyz,
50 | a.scripts,
51 | [],
52 | exclude_binaries=True,
53 | name="PyMODA",
54 | debug=False,
55 | bootloader_ignore_signals=False,
56 | strip=False,
57 | upx=True,
58 | console=False,
59 | )
60 |
61 | coll = COLLECT(
62 | exe,
63 | a.binaries,
64 | a.zipfiles,
65 | a.datas,
66 | strip=False,
67 | upx=True,
68 | upx_exclude=[],
69 | name="main",
70 | )
71 |
72 | app = BUNDLE(coll,
73 | name='PyMODA.app',
74 | icon=None,
75 | bundle_identifier="com.luphysics.pymoda")
--------------------------------------------------------------------------------
/main.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python ; coding: utf-8 -*-
2 |
3 | block_cipher = None
4 |
5 | import os
6 | import os.path
7 |
8 | def find_packages():
9 | from pathlib import Path
10 |
11 | out = []
12 |
13 | for f in Path(".").rglob("**/for_redistribution_files_only/*"):
14 | head, tail = os.path.split(f)
15 |
16 | if os.path.isdir(f) and tail.lower() in head.lower():
17 | out.append((f, tail,))
18 |
19 | return out
20 |
21 |
22 | data = [
23 | ("res", "res"),
24 | ("LICENSE", "."),
25 | *find_packages(),
26 | ]
27 |
28 | a = Analysis(
29 | ["src/main.py"],
30 | pathex=[os.getcwd()],
31 | binaries=[],
32 | datas=data,
33 | hiddenimports=[
34 | "qasync",
35 | "gui.dialogs.files.DragDropLabel",
36 | "pkg_resources.py2_warn",
37 | ],
38 | hookspath=[],
39 | runtime_hooks=[],
40 | excludes=[],
41 | win_no_prefer_redirects=False,
42 | win_private_assemblies=False,
43 | cipher=block_cipher,
44 | noarchive=False,
45 | )
46 |
47 | pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
48 |
49 | exe = EXE(
50 | pyz,
51 | a.scripts,
52 | [],
53 | exclude_binaries=True,
54 | name="PyMODA",
55 | debug=False,
56 | bootloader_ignore_signals=False,
57 | strip=False,
58 | upx=True,
59 | console=True,
60 | )
61 |
62 | coll = COLLECT(
63 | exe,
64 | a.binaries,
65 | a.zipfiles,
66 | a.datas,
67 | strip=False,
68 | upx=True,
69 | upx_exclude=[],
70 | name="main",
71 | )
72 |
--------------------------------------------------------------------------------
/packages/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Table of Contents
4 |
5 | - [packages](#packages)
6 |
7 |
8 |
9 | ## packages
10 |
11 | The `packages` folder contains the MATLAB-packaged Python libraries used by PyMODA.
12 |
13 | ### install.py
14 |
15 | `install.py` is a Python script which installs the Python packages from this folder, and uses pip to install the
16 | requirements from `requirements.txt` in the root folder.
17 |
18 | To specify a particular Python version to use, add it as a command-line argument. For example, `sudo python3 install.py python3.7` will install the packages with `python3.7` even if `python3` is Python 3.6.
--------------------------------------------------------------------------------
/packages/WFT/for_redistribution/MyAppInstaller_web.install:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/WFT/for_redistribution/MyAppInstaller_web.install
--------------------------------------------------------------------------------
/packages/WFT/for_redistribution_files_only/WFT/WFT.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/WFT/for_redistribution_files_only/WFT/WFT.ctf
--------------------------------------------------------------------------------
/packages/WFT/for_redistribution_files_only/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'WFT'
28 | ],
29 | package_data={'WFT': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/WFT/for_testing/WFT/WFT.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/WFT/for_testing/WFT/WFT.ctf
--------------------------------------------------------------------------------
/packages/WFT/for_testing/readme.txt:
--------------------------------------------------------------------------------
1 | WFT MATLAB Python Package
2 |
3 | 1. Prerequisites for Deployment
4 |
5 | Verify that version 9.6 (R2019a) of the MATLAB Runtime is installed.
6 | If not, you can run the MATLAB Runtime installer.
7 | To find its location, enter
8 |
9 | >>mcrinstaller
10 |
11 | at the MATLAB prompt.
12 |
13 | Alternatively, download and install the Linux version of the MATLAB Runtime for R2019a
14 | from the following link on the MathWorks website:
15 |
16 | http://www.mathworks.com/products/compiler/mcr/index.html
17 |
18 | For more information about the MATLAB Runtime and the MATLAB Runtime installer, see
19 | "Distribute Applications" in the MATLAB Compiler SDK documentation
20 | in the MathWorks Documentation Center.
21 |
22 | Verify that a Linux version of Python 2.7, 3.5, 3.6, and/or 3.7 is installed.
23 |
24 | 2. Installing the WFT Package
25 |
26 | A. Change to the directory that contains the file setup.py and the subdirectory WFT. If
27 | you do not have write permissions, copy all its contents to a temporary location and
28 | change to that directory.
29 |
30 | B. Execute the command:
31 |
32 | python setup.py install [options]
33 |
34 | If you have full administrator privileges, and install to the default location, you do
35 | not need to specify any options. Otherwise, use --user to install to your home folder, or
36 | --prefix="installdir" to install to "installdir". In the latter case, add "installdir" to
37 | the PYTHONPATH environment variable. For details, refer to:
38 |
39 | https://docs.python.org/2/install/index.html
40 |
41 | C. Set environment variables as follows:
42 |
43 | In the following directions, replace MR/v96 by the directory on the target machine where MATLAB is installed, or MR by the directory where the MATLAB Runtime is installed.
44 |
45 | (1) Set the environment variable XAPPLRESDIR to this value:
46 |
47 | MR/v96/X11/app-defaults
48 |
49 |
50 | (2) If the environment variable LD_LIBRARY_PATH is undefined, set it to the following:
51 |
52 | MR/v96/runtime/glnxa64:MR/v96/bin/glnxa64:MR/v96/sys/os/glnxa64:MR/v96/sys/opengl/lib/glnxa64
53 |
54 | If it is defined, set it to the following:
55 |
56 | ${LD_LIBRARY_PATH}:MR/v96/runtime/glnxa64:MR/v96/bin/glnxa64:MR/v96/sys/os/glnxa64:MR/v96/sys/opengl/lib/glnxa64
57 |
58 | 3. Using the WFT Package
59 |
60 | The WFT package is on your Python path. To import it into a Python script or session,
61 | execute:
62 |
63 | import WFT
64 |
65 | If a namespace must be specified for the package, modify the import statement accordingly.
66 |
--------------------------------------------------------------------------------
/packages/WFT/for_testing/requiredMCRProducts.txt:
--------------------------------------------------------------------------------
1 | 35010 35000
--------------------------------------------------------------------------------
/packages/WFT/for_testing/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'WFT'
28 | ],
29 | package_data={'WFT': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/WT/for_redistribution/MyAppInstaller_web.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/WT/for_redistribution/MyAppInstaller_web.exe
--------------------------------------------------------------------------------
/packages/WT/for_redistribution/MyAppInstaller_web.install:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/WT/for_redistribution/MyAppInstaller_web.install
--------------------------------------------------------------------------------
/packages/WT/for_redistribution_files_only/WT/WT.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/WT/for_redistribution_files_only/WT/WT.ctf
--------------------------------------------------------------------------------
/packages/WT/for_redistribution_files_only/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'WT'
28 | ],
29 | package_data={'WT': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/WT/for_redistribution_files_only/wt_test/wt_test.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/WT/for_redistribution_files_only/wt_test/wt_test.ctf
--------------------------------------------------------------------------------
/packages/WT/for_testing/WT/WT.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/WT/for_testing/WT/WT.ctf
--------------------------------------------------------------------------------
/packages/WT/for_testing/readme.txt:
--------------------------------------------------------------------------------
1 | WT MATLAB Python Package
2 |
3 | 1. Prerequisites for Deployment
4 |
5 | Verify that version 9.6 (R2019a) of the MATLAB Runtime is installed.
6 | If not, you can run the MATLAB Runtime installer.
7 | To find its location, enter
8 |
9 | >>mcrinstaller
10 |
11 | at the MATLAB prompt.
12 | NOTE: You will need administrator rights to run the MATLAB Runtime installer.
13 |
14 | Alternatively, download and install the Windows version of the MATLAB Runtime for R2019a
15 | from the following link on the MathWorks website:
16 |
17 | http://www.mathworks.com/products/compiler/mcr/index.html
18 |
19 | For more information about the MATLAB Runtime and the MATLAB Runtime installer, see
20 | "Distribute Applications" in the MATLAB Compiler SDK documentation
21 | in the MathWorks Documentation Center.
22 |
23 | Verify that a Windows version of Python 2.7, 3.5, 3.6, and/or 3.7 is installed.
24 |
25 | 2. Installing the WT Package
26 |
27 | A. Change to the directory that contains the file setup.py and the subdirectory WT. If
28 | you do not have write permissions, copy all its contents to a temporary location and
29 | change to that directory.
30 |
31 | B. Execute the command:
32 |
33 | python setup.py install [options]
34 |
35 | If you have full administrator privileges, and install to the default location, you do
36 | not need to specify any options. Otherwise, use --user to install to your home folder, or
37 | --prefix="installdir" to install to "installdir". In the latter case, add "installdir" to
38 | the PYTHONPATH environment variable. For details, refer to:
39 |
40 | https://docs.python.org/2/install/index.html
41 |
42 |
43 | 3. Using the WT Package
44 |
45 | The WT package is on your Python path. To import it into a Python script or session,
46 | execute:
47 |
48 | import WT
49 |
50 | If a namespace must be specified for the package, modify the import statement accordingly.
51 |
--------------------------------------------------------------------------------
/packages/WT/for_testing/requiredMCRProducts.txt:
--------------------------------------------------------------------------------
1 | 35010 35000
--------------------------------------------------------------------------------
/packages/WT/for_testing/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'WT'
28 | ],
29 | package_data={'WT': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/WT/for_testing/wt_test/wt_test.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/WT/for_testing/wt_test/wt_test.ctf
--------------------------------------------------------------------------------
/packages/biphaseWavPython/for_redistribution/MyAppInstaller_web.install:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/biphaseWavPython/for_redistribution/MyAppInstaller_web.install
--------------------------------------------------------------------------------
/packages/biphaseWavPython/for_redistribution_files_only/biphaseWavPython/biphaseWavPython.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/biphaseWavPython/for_redistribution_files_only/biphaseWavPython/biphaseWavPython.ctf
--------------------------------------------------------------------------------
/packages/biphaseWavPython/for_redistribution_files_only/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'biphaseWavPython'
28 | ],
29 | package_data={'biphaseWavPython': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/biphaseWavPython/for_testing/biphaseWavPython/biphaseWavPython.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/biphaseWavPython/for_testing/biphaseWavPython/biphaseWavPython.ctf
--------------------------------------------------------------------------------
/packages/biphaseWavPython/for_testing/readme.txt:
--------------------------------------------------------------------------------
1 | biphaseWavPython MATLAB Python Package
2 |
3 | 1. Prerequisites for Deployment
4 |
5 | Verify that version 9.6 (R2019a) of the MATLAB Runtime is installed.
6 | If not, you can run the MATLAB Runtime installer.
7 | To find its location, enter
8 |
9 | >>mcrinstaller
10 |
11 | at the MATLAB prompt.
12 |
13 | Alternatively, download and install the Linux version of the MATLAB Runtime for R2019a
14 | from the following link on the MathWorks website:
15 |
16 | http://www.mathworks.com/products/compiler/mcr/index.html
17 |
18 | For more information about the MATLAB Runtime and the MATLAB Runtime installer, see
19 | "Distribute Applications" in the MATLAB Compiler SDK documentation
20 | in the MathWorks Documentation Center.
21 |
22 | Verify that a Linux version of Python 2.7, 3.5, 3.6, and/or 3.7 is installed.
23 |
24 | 2. Installing the biphaseWavPython Package
25 |
26 | A. Change to the directory that contains the file setup.py and the subdirectory
27 | biphaseWavPython. If you do not have write permissions, copy all its contents to a
28 | temporary location and change to that directory.
29 |
30 | B. Execute the command:
31 |
32 | python setup.py install [options]
33 |
34 | If you have full administrator privileges, and install to the default location, you do
35 | not need to specify any options. Otherwise, use --user to install to your home folder, or
36 | --prefix="installdir" to install to "installdir". In the latter case, add "installdir" to
37 | the PYTHONPATH environment variable. For details, refer to:
38 |
39 | https://docs.python.org/2/install/index.html
40 |
41 | C. Set environment variables as follows:
42 |
43 | In the following directions, replace MR/v96 by the directory on the target machine where MATLAB is installed, or MR by the directory where the MATLAB Runtime is installed.
44 |
45 | (1) Set the environment variable XAPPLRESDIR to this value:
46 |
47 | MR/v96/X11/app-defaults
48 |
49 |
50 | (2) If the environment variable LD_LIBRARY_PATH is undefined, set it to the following:
51 |
52 | MR/v96/runtime/glnxa64:MR/v96/bin/glnxa64:MR/v96/sys/os/glnxa64:MR/v96/sys/opengl/lib/glnxa64
53 |
54 | If it is defined, set it to the following:
55 |
56 | ${LD_LIBRARY_PATH}:MR/v96/runtime/glnxa64:MR/v96/bin/glnxa64:MR/v96/sys/os/glnxa64:MR/v96/sys/opengl/lib/glnxa64
57 |
58 | 3. Using the biphaseWavPython Package
59 |
60 | The biphaseWavPython package is on your Python path. To import it into a Python script or
61 | session, execute:
62 |
63 | import biphaseWavPython
64 |
65 | If a namespace must be specified for the package, modify the import statement accordingly.
66 |
--------------------------------------------------------------------------------
/packages/biphaseWavPython/for_testing/requiredMCRProducts.txt:
--------------------------------------------------------------------------------
1 | 35010
--------------------------------------------------------------------------------
/packages/biphaseWavPython/for_testing/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'biphaseWavPython'
28 | ],
29 | package_data={'biphaseWavPython': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/bispecWavPython/for_redistribution/MyAppInstaller_web.install:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/bispecWavPython/for_redistribution/MyAppInstaller_web.install
--------------------------------------------------------------------------------
/packages/bispecWavPython/for_redistribution_files_only/bispecWavPython/bispecWavPython.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/bispecWavPython/for_redistribution_files_only/bispecWavPython/bispecWavPython.ctf
--------------------------------------------------------------------------------
/packages/bispecWavPython/for_redistribution_files_only/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'bispecWavPython'
28 | ],
29 | package_data={'bispecWavPython': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/bispecWavPython/for_testing/bispecWavPython/bispecWavPython.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/bispecWavPython/for_testing/bispecWavPython/bispecWavPython.ctf
--------------------------------------------------------------------------------
/packages/bispecWavPython/for_testing/readme.txt:
--------------------------------------------------------------------------------
1 | bispecWavPython MATLAB Python Package
2 |
3 | 1. Prerequisites for Deployment
4 |
5 | Verify that version 9.6 (R2019a) of the MATLAB Runtime is installed.
6 | If not, you can run the MATLAB Runtime installer.
7 | To find its location, enter
8 |
9 | >>mcrinstaller
10 |
11 | at the MATLAB prompt.
12 |
13 | Alternatively, download and install the Linux version of the MATLAB Runtime for R2019a
14 | from the following link on the MathWorks website:
15 |
16 | http://www.mathworks.com/products/compiler/mcr/index.html
17 |
18 | For more information about the MATLAB Runtime and the MATLAB Runtime installer, see
19 | "Distribute Applications" in the MATLAB Compiler SDK documentation
20 | in the MathWorks Documentation Center.
21 |
22 | Verify that a Linux version of Python 2.7, 3.5, 3.6, and/or 3.7 is installed.
23 |
24 | 2. Installing the bispecWavPython Package
25 |
26 | A. Change to the directory that contains the file setup.py and the subdirectory
27 | bispecWavPython. If you do not have write permissions, copy all its contents to a
28 | temporary location and change to that directory.
29 |
30 | B. Execute the command:
31 |
32 | python setup.py install [options]
33 |
34 | If you have full administrator privileges, and install to the default location, you do
35 | not need to specify any options. Otherwise, use --user to install to your home folder, or
36 | --prefix="installdir" to install to "installdir". In the latter case, add "installdir" to
37 | the PYTHONPATH environment variable. For details, refer to:
38 |
39 | https://docs.python.org/2/install/index.html
40 |
41 | C. Set environment variables as follows:
42 |
43 | In the following directions, replace MR/v96 by the directory on the target machine where MATLAB is installed, or MR by the directory where the MATLAB Runtime is installed.
44 |
45 | (1) Set the environment variable XAPPLRESDIR to this value:
46 |
47 | MR/v96/X11/app-defaults
48 |
49 |
50 | (2) If the environment variable LD_LIBRARY_PATH is undefined, set it to the following:
51 |
52 | MR/v96/runtime/glnxa64:MR/v96/bin/glnxa64:MR/v96/sys/os/glnxa64:MR/v96/sys/opengl/lib/glnxa64
53 |
54 | If it is defined, set it to the following:
55 |
56 | ${LD_LIBRARY_PATH}:MR/v96/runtime/glnxa64:MR/v96/bin/glnxa64:MR/v96/sys/os/glnxa64:MR/v96/sys/opengl/lib/glnxa64
57 |
58 | 3. Using the bispecWavPython Package
59 |
60 | The bispecWavPython package is on your Python path. To import it into a Python script or
61 | session, execute:
62 |
63 | import bispecWavPython
64 |
65 | If a namespace must be specified for the package, modify the import statement accordingly.
66 |
--------------------------------------------------------------------------------
/packages/bispecWavPython/for_testing/requiredMCRProducts.txt:
--------------------------------------------------------------------------------
1 | 35010 35119 35000
--------------------------------------------------------------------------------
/packages/bispecWavPython/for_testing/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'bispecWavPython'
28 | ],
29 | package_data={'bispecWavPython': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/ecurve/for_redistribution/MyAppInstaller_web.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/ecurve/for_redistribution/MyAppInstaller_web.exe
--------------------------------------------------------------------------------
/packages/ecurve/for_redistribution/MyAppInstaller_web.install:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/ecurve/for_redistribution/MyAppInstaller_web.install
--------------------------------------------------------------------------------
/packages/ecurve/for_redistribution_files_only/ecurve/ecurve.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/ecurve/for_redistribution_files_only/ecurve/ecurve.ctf
--------------------------------------------------------------------------------
/packages/ecurve/for_redistribution_files_only/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'ecurve'
28 | ],
29 | package_data={'ecurve': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/ecurve/for_testing/ecurve/ecurve.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/ecurve/for_testing/ecurve/ecurve.ctf
--------------------------------------------------------------------------------
/packages/ecurve/for_testing/readme.txt:
--------------------------------------------------------------------------------
1 | ecurve MATLAB Python Package
2 |
3 | 1. Prerequisites for Deployment
4 |
5 | Verify that version 9.6 (R2019a) of the MATLAB Runtime is installed.
6 | If not, you can run the MATLAB Runtime installer.
7 | To find its location, enter
8 |
9 | >>mcrinstaller
10 |
11 | at the MATLAB prompt.
12 | NOTE: You will need administrator rights to run the MATLAB Runtime installer.
13 |
14 | Alternatively, download and install the Windows version of the MATLAB Runtime for R2019a
15 | from the following link on the MathWorks website:
16 |
17 | http://www.mathworks.com/products/compiler/mcr/index.html
18 |
19 | For more information about the MATLAB Runtime and the MATLAB Runtime installer, see
20 | "Distribute Applications" in the MATLAB Compiler SDK documentation
21 | in the MathWorks Documentation Center.
22 |
23 | Verify that a Windows version of Python 2.7, 3.5, 3.6, and/or 3.7 is installed.
24 |
25 | 2. Installing the ecurve Package
26 |
27 | A. Change to the directory that contains the file setup.py and the subdirectory ecurve.
28 | If you do not have write permissions, copy all its contents to a temporary location and
29 | change to that directory.
30 |
31 | B. Execute the command:
32 |
33 | python setup.py install [options]
34 |
35 | If you have full administrator privileges, and install to the default location, you do
36 | not need to specify any options. Otherwise, use --user to install to your home folder, or
37 | --prefix="installdir" to install to "installdir". In the latter case, add "installdir" to
38 | the PYTHONPATH environment variable. For details, refer to:
39 |
40 | https://docs.python.org/2/install/index.html
41 |
42 |
43 | 3. Using the ecurve Package
44 |
45 | The ecurve package is on your Python path. To import it into a Python script or session,
46 | execute:
47 |
48 | import ecurve
49 |
50 | If a namespace must be specified for the package, modify the import statement accordingly.
51 |
--------------------------------------------------------------------------------
/packages/ecurve/for_testing/requiredMCRProducts.txt:
--------------------------------------------------------------------------------
1 | 35010 35000
--------------------------------------------------------------------------------
/packages/ecurve/for_testing/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'ecurve'
28 | ],
29 | package_data={'ecurve': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/full_bayesian/for_redistribution/MyAppInstaller_web.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/full_bayesian/for_redistribution/MyAppInstaller_web.exe
--------------------------------------------------------------------------------
/packages/full_bayesian/for_redistribution_files_only/full_bayesian/full_bayesian.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/full_bayesian/for_redistribution_files_only/full_bayesian/full_bayesian.ctf
--------------------------------------------------------------------------------
/packages/full_bayesian/for_redistribution_files_only/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'full_bayesian'
28 | ],
29 | package_data={'full_bayesian': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/full_bayesian/for_testing/full_bayesian/full_bayesian.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/full_bayesian/for_testing/full_bayesian/full_bayesian.ctf
--------------------------------------------------------------------------------
/packages/full_bayesian/for_testing/readme.txt:
--------------------------------------------------------------------------------
1 | full_bayesian MATLAB Python Package
2 |
3 | 1. Prerequisites for Deployment
4 |
5 | Verify that version 9.6 (R2019a) of the MATLAB Runtime is installed.
6 | If not, you can run the MATLAB Runtime installer.
7 | To find its location, enter
8 |
9 | >>mcrinstaller
10 |
11 | at the MATLAB prompt.
12 | NOTE: You will need administrator rights to run the MATLAB Runtime installer.
13 |
14 | Alternatively, download and install the Windows version of the MATLAB Runtime for R2019a
15 | from the following link on the MathWorks website:
16 |
17 | http://www.mathworks.com/products/compiler/mcr/index.html
18 |
19 | For more information about the MATLAB Runtime and the MATLAB Runtime installer, see
20 | "Distribute Applications" in the MATLAB Compiler SDK documentation
21 | in the MathWorks Documentation Center.
22 |
23 | Verify that a Windows version of Python 2.7, 3.5, 3.6, and/or 3.7 is installed.
24 |
25 | 2. Installing the full_bayesian Package
26 |
27 | A. Change to the directory that contains the file setup.py and the subdirectory
28 | full_bayesian. If you do not have write permissions, copy all its contents to a temporary
29 | location and change to that directory.
30 |
31 | B. Execute the command:
32 |
33 | python setup.py install [options]
34 |
35 | If you have full administrator privileges, and install to the default location, you do
36 | not need to specify any options. Otherwise, use --user to install to your home folder, or
37 | --prefix="installdir" to install to "installdir". In the latter case, add "installdir" to
38 | the PYTHONPATH environment variable. For details, refer to:
39 |
40 | https://docs.python.org/2/install/index.html
41 |
42 |
43 | 3. Using the full_bayesian Package
44 |
45 | The full_bayesian package is on your Python path. To import it into a Python script or
46 | session, execute:
47 |
48 | import full_bayesian
49 |
50 | If a namespace must be specified for the package, modify the import statement accordingly.
51 |
--------------------------------------------------------------------------------
/packages/full_bayesian/for_testing/requiredMCRProducts.txt:
--------------------------------------------------------------------------------
1 | 35000 35010
--------------------------------------------------------------------------------
/packages/full_bayesian/for_testing/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'full_bayesian'
28 | ],
29 | package_data={'full_bayesian': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/rectfr/for_redistribution/MyAppInstaller_web.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/rectfr/for_redistribution/MyAppInstaller_web.exe
--------------------------------------------------------------------------------
/packages/rectfr/for_redistribution/MyAppInstaller_web.install:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/rectfr/for_redistribution/MyAppInstaller_web.install
--------------------------------------------------------------------------------
/packages/rectfr/for_redistribution_files_only/rectfr/rectfr.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/rectfr/for_redistribution_files_only/rectfr/rectfr.ctf
--------------------------------------------------------------------------------
/packages/rectfr/for_redistribution_files_only/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'rectfr'
28 | ],
29 | package_data={'rectfr': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/rectfr/for_testing/readme.txt:
--------------------------------------------------------------------------------
1 | rectfr MATLAB Python Package
2 |
3 | 1. Prerequisites for Deployment
4 |
5 | Verify that version 9.6 (R2019a) of the MATLAB Runtime is installed.
6 | If not, you can run the MATLAB Runtime installer.
7 | To find its location, enter
8 |
9 | >>mcrinstaller
10 |
11 | at the MATLAB prompt.
12 | NOTE: You will need administrator rights to run the MATLAB Runtime installer.
13 |
14 | Alternatively, download and install the Windows version of the MATLAB Runtime for R2019a
15 | from the following link on the MathWorks website:
16 |
17 | http://www.mathworks.com/products/compiler/mcr/index.html
18 |
19 | For more information about the MATLAB Runtime and the MATLAB Runtime installer, see
20 | "Distribute Applications" in the MATLAB Compiler SDK documentation
21 | in the MathWorks Documentation Center.
22 |
23 | Verify that a Windows version of Python 2.7, 3.5, 3.6, and/or 3.7 is installed.
24 |
25 | 2. Installing the rectfr Package
26 |
27 | A. Change to the directory that contains the file setup.py and the subdirectory rectfr.
28 | If you do not have write permissions, copy all its contents to a temporary location and
29 | change to that directory.
30 |
31 | B. Execute the command:
32 |
33 | python setup.py install [options]
34 |
35 | If you have full administrator privileges, and install to the default location, you do
36 | not need to specify any options. Otherwise, use --user to install to your home folder, or
37 | --prefix="installdir" to install to "installdir". In the latter case, add "installdir" to
38 | the PYTHONPATH environment variable. For details, refer to:
39 |
40 | https://docs.python.org/2/install/index.html
41 |
42 |
43 | 3. Using the rectfr Package
44 |
45 | The rectfr package is on your Python path. To import it into a Python script or session,
46 | execute:
47 |
48 | import rectfr
49 |
50 | If a namespace must be specified for the package, modify the import statement accordingly.
51 |
--------------------------------------------------------------------------------
/packages/rectfr/for_testing/rectfr/rectfr.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/rectfr/for_testing/rectfr/rectfr.ctf
--------------------------------------------------------------------------------
/packages/rectfr/for_testing/requiredMCRProducts.txt:
--------------------------------------------------------------------------------
1 | 35010
--------------------------------------------------------------------------------
/packages/rectfr/for_testing/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'rectfr'
28 | ],
29 | package_data={'rectfr': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/ridge_extraction/for_redistribution/MyAppInstaller_web.install:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/ridge_extraction/for_redistribution/MyAppInstaller_web.install
--------------------------------------------------------------------------------
/packages/ridge_extraction/for_redistribution_files_only/ridge_extraction/ridge_extraction.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/ridge_extraction/for_redistribution_files_only/ridge_extraction/ridge_extraction.ctf
--------------------------------------------------------------------------------
/packages/ridge_extraction/for_redistribution_files_only/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'ridge_extraction'
28 | ],
29 | package_data={'ridge_extraction': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/ridge_extraction/for_testing/readme.txt:
--------------------------------------------------------------------------------
1 | ridge_extraction MATLAB Python Package
2 |
3 | 1. Prerequisites for Deployment
4 |
5 | Verify that version 9.6 (R2019a) of the MATLAB Runtime is installed.
6 | If not, you can run the MATLAB Runtime installer.
7 | To find its location, enter
8 |
9 | >>mcrinstaller
10 |
11 | at the MATLAB prompt.
12 |
13 | Alternatively, download and install the Linux version of the MATLAB Runtime for R2019a
14 | from the following link on the MathWorks website:
15 |
16 | http://www.mathworks.com/products/compiler/mcr/index.html
17 |
18 | For more information about the MATLAB Runtime and the MATLAB Runtime installer, see
19 | "Distribute Applications" in the MATLAB Compiler SDK documentation
20 | in the MathWorks Documentation Center.
21 |
22 | Verify that a Linux version of Python 2.7, 3.5, 3.6, and/or 3.7 is installed.
23 |
24 | 2. Installing the ridge_extraction Package
25 |
26 | A. Change to the directory that contains the file setup.py and the subdirectory
27 | ridge_extraction. If you do not have write permissions, copy all its contents to a
28 | temporary location and change to that directory.
29 |
30 | B. Execute the command:
31 |
32 | python setup.py install [options]
33 |
34 | If you have full administrator privileges, and install to the default location, you do
35 | not need to specify any options. Otherwise, use --user to install to your home folder, or
36 | --prefix="installdir" to install to "installdir". In the latter case, add "installdir" to
37 | the PYTHONPATH environment variable. For details, refer to:
38 |
39 | https://docs.python.org/2/install/index.html
40 |
41 | C. Set environment variables as follows:
42 |
43 | In the following directions, replace MR/v96 by the directory on the target machine where MATLAB is installed, or MR by the directory where the MATLAB Runtime is installed.
44 |
45 | (1) Set the environment variable XAPPLRESDIR to this value:
46 |
47 | MR/v96/X11/app-defaults
48 |
49 |
50 | (2) If the environment variable LD_LIBRARY_PATH is undefined, set it to the following:
51 |
52 | MR/v96/runtime/glnxa64:MR/v96/bin/glnxa64:MR/v96/sys/os/glnxa64:MR/v96/sys/opengl/lib/glnxa64
53 |
54 | If it is defined, set it to the following:
55 |
56 | ${LD_LIBRARY_PATH}:MR/v96/runtime/glnxa64:MR/v96/bin/glnxa64:MR/v96/sys/os/glnxa64:MR/v96/sys/opengl/lib/glnxa64
57 |
58 | 3. Using the ridge_extraction Package
59 |
60 | The ridge_extraction package is on your Python path. To import it into a Python script or
61 | session, execute:
62 |
63 | import ridge_extraction
64 |
65 | If a namespace must be specified for the package, modify the import statement accordingly.
66 |
--------------------------------------------------------------------------------
/packages/ridge_extraction/for_testing/requiredMCRProducts.txt:
--------------------------------------------------------------------------------
1 | 35010 35000
--------------------------------------------------------------------------------
/packages/ridge_extraction/for_testing/ridge_extraction/ridge_extraction.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/ridge_extraction/for_testing/ridge_extraction/ridge_extraction.ctf
--------------------------------------------------------------------------------
/packages/ridge_extraction/for_testing/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'ridge_extraction'
28 | ],
29 | package_data={'ridge_extraction': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/wavsurrogate/for_redistribution/MyAppInstaller_web.install:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/wavsurrogate/for_redistribution/MyAppInstaller_web.install
--------------------------------------------------------------------------------
/packages/wavsurrogate/for_redistribution_files_only/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'wavsurrogate'
28 | ],
29 | package_data={'wavsurrogate': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/wavsurrogate/for_redistribution_files_only/wavsurrogate/wavsurrogate.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/wavsurrogate/for_redistribution_files_only/wavsurrogate/wavsurrogate.ctf
--------------------------------------------------------------------------------
/packages/wavsurrogate/for_testing/readme.txt:
--------------------------------------------------------------------------------
1 | wavsurrogate MATLAB Python Package
2 |
3 | 1. Prerequisites for Deployment
4 |
5 | Verify that version 9.6 (R2019a) of the MATLAB Runtime is installed.
6 | If not, you can run the MATLAB Runtime installer.
7 | To find its location, enter
8 |
9 | >>mcrinstaller
10 |
11 | at the MATLAB prompt.
12 |
13 | Alternatively, download and install the Linux version of the MATLAB Runtime for R2019a
14 | from the following link on the MathWorks website:
15 |
16 | http://www.mathworks.com/products/compiler/mcr/index.html
17 |
18 | For more information about the MATLAB Runtime and the MATLAB Runtime installer, see
19 | "Distribute Applications" in the MATLAB Compiler SDK documentation
20 | in the MathWorks Documentation Center.
21 |
22 | Verify that a Linux version of Python 2.7, 3.5, 3.6, and/or 3.7 is installed.
23 |
24 | 2. Installing the wavsurrogate Package
25 |
26 | A. Change to the directory that contains the file setup.py and the subdirectory
27 | wavsurrogate. If you do not have write permissions, copy all its contents to a temporary
28 | location and change to that directory.
29 |
30 | B. Execute the command:
31 |
32 | python setup.py install [options]
33 |
34 | If you have full administrator privileges, and install to the default location, you do
35 | not need to specify any options. Otherwise, use --user to install to your home folder, or
36 | --prefix="installdir" to install to "installdir". In the latter case, add "installdir" to
37 | the PYTHONPATH environment variable. For details, refer to:
38 |
39 | https://docs.python.org/2/install/index.html
40 |
41 | C. Set environment variables as follows:
42 |
43 | In the following directions, replace MR/v96 by the directory on the target machine where MATLAB is installed, or MR by the directory where the MATLAB Runtime is installed.
44 |
45 | (1) Set the environment variable XAPPLRESDIR to this value:
46 |
47 | MR/v96/X11/app-defaults
48 |
49 |
50 | (2) If the environment variable LD_LIBRARY_PATH is undefined, set it to the following:
51 |
52 | MR/v96/runtime/glnxa64:MR/v96/bin/glnxa64:MR/v96/sys/os/glnxa64:MR/v96/sys/opengl/lib/glnxa64
53 |
54 | If it is defined, set it to the following:
55 |
56 | ${LD_LIBRARY_PATH}:MR/v96/runtime/glnxa64:MR/v96/bin/glnxa64:MR/v96/sys/os/glnxa64:MR/v96/sys/opengl/lib/glnxa64
57 |
58 | 3. Using the wavsurrogate Package
59 |
60 | The wavsurrogate package is on your Python path. To import it into a Python script or
61 | session, execute:
62 |
63 | import wavsurrogate
64 |
65 | If a namespace must be specified for the package, modify the import statement accordingly.
66 |
--------------------------------------------------------------------------------
/packages/wavsurrogate/for_testing/requiredMCRProducts.txt:
--------------------------------------------------------------------------------
1 | 35010 35000
--------------------------------------------------------------------------------
/packages/wavsurrogate/for_testing/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015-2018 The MathWorks, Inc.
2 |
3 | from distutils.core import setup
4 | from distutils.command.clean import clean
5 | from distutils.command.install import install
6 |
7 | class InstallRuntime(install):
8 | # Calls the default run command, then deletes the build area
9 | # (equivalent to "setup clean --all").
10 | def run(self):
11 | install.run(self)
12 | c = clean(self.distribution)
13 | c.all = True
14 | c.finalize_options()
15 | c.run()
16 |
17 | if __name__ == '__main__':
18 |
19 | setup(
20 | name="matlabruntimeforpython",
21 | version="R2019a",
22 | description='A module to call MATLAB from Python',
23 | author='MathWorks',
24 | url='https://www.mathworks.com/',
25 | platforms=['Linux', 'Windows', 'MacOS'],
26 | packages=[
27 | 'wavsurrogate'
28 | ],
29 | package_data={'wavsurrogate': ['*.ctf']},
30 | # Executes the custom code above in order to delete the build area.
31 | cmdclass={'install': InstallRuntime}
32 | )
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/wavsurrogate/for_testing/wavsurrogate/wavsurrogate.ctf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/packages/wavsurrogate/for_testing/wavsurrogate/wavsurrogate.ctf
--------------------------------------------------------------------------------
/publish_update.py:
--------------------------------------------------------------------------------
1 | """
2 | Python script which automates the task of publishing an update to PyMODA.
3 |
4 | Example usage:
5 | - python publish_update.py v0.6.0
6 | - python publish_update.py v0.6.0 --push
7 | """
8 | import os
9 | import sys
10 | from typing import List
11 |
12 | os.chdir(os.path.abspath(os.path.dirname(__file__)))
13 | args = sys.argv
14 |
15 | if len(args) <= 1:
16 | print("Please supply the new version tag as a command-line argument.")
17 | sys.exit(0)
18 |
19 |
20 | tag = sys.argv[1]
21 | if not tag.startswith("v"):
22 | tag = f"v{tag}"
23 |
24 | push = any([a in ["push", "--push"] for a in args[1:]])
25 |
26 |
27 | def replace_version(lines: List[str]) -> List[str]:
28 | out = []
29 |
30 | for l in lines:
31 | if not l.startswith("__version__"):
32 | out.append(l)
33 | else:
34 | out.append(f"__version__ = \"{tag.replace('v', '')}\"\n")
35 |
36 | return out
37 |
38 |
39 | with open("src/main.py", "r") as f:
40 | lines = f.readlines()
41 |
42 | with open("src/main.py", "w") as f:
43 | f.writelines(replace_version(lines))
44 |
45 | # Run twice to ensure that pre-commit hooks are satisfied.
46 | for _ in range(2):
47 | os.system(f"git add src/main.py")
48 | os.system(f"git commit -m \"Bump version to {tag}\"")
49 |
50 | print(f"Tagging release as '{tag}'.")
51 | os.system(f"git tag {tag}")
52 |
53 | if push:
54 | os.system("git push -u")
55 | os.system(f"git push origin {tag}")
56 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohttp==3.6.2
2 | AsyncProcessScheduler==0.9.0b1
3 | dataclasses==0.6
4 | EasySettings==4.0.0
5 | matplotlib==3.1.1
6 | multiprocess==0.70.8
7 | numpy==1.18.3
8 | pre-commit==1.18.3
9 | PyGithub==1.46
10 | PyMODAlib==0.11.2b1
11 | PyOpenGL==3.1.0
12 | PyQt5==5.14.2
13 | PyQt5-sip==12.7.0
14 | PyQt5-stubs==5.14.2
15 | PyQtGraph==0.10.0
16 | scipy==1.4.1
17 | psutil==5.7.0
18 | qasync==0.9.4
--------------------------------------------------------------------------------
/res/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Table of Contents
4 |
5 | - [res](#res)
6 |
7 |
8 |
9 | ## res
10 |
11 | The `res` folder contains the resources used by PyMODA.
12 |
13 | | Subfolder | Contents |
14 | | ----- | ----- |
15 | | `colours` | Colourmaps |
16 | | `img` | Images |
17 | | `layout` | Layout files which are produced by Qt Designer |
18 | | `data` | Data files which are used to test the program |
--------------------------------------------------------------------------------
/res/data/butter.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/butter.mat
--------------------------------------------------------------------------------
/res/data/mat/1signal_10Hz.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/1signal_10Hz.mat
--------------------------------------------------------------------------------
/res/data/mat/2signals_10Hz.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/2signals_10Hz.mat
--------------------------------------------------------------------------------
/res/data/mat/6signals_10Hz.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/6signals_10Hz.mat
--------------------------------------------------------------------------------
/res/data/mat/IEEEsigs/IEEEex_10Hz.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/IEEEsigs/IEEEex_10Hz.mat
--------------------------------------------------------------------------------
/res/data/mat/IEEEsigs/xp_100Hz.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/IEEEsigs/xp_100Hz.mat
--------------------------------------------------------------------------------
/res/data/mat/IEEEsigs/xp_10Hz.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/IEEEsigs/xp_10Hz.mat
--------------------------------------------------------------------------------
/res/data/mat/fm_square_200Hz.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/fm_square_200Hz.mat
--------------------------------------------------------------------------------
/res/data/mat/freq_mod_200Hz.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/freq_mod_200Hz.mat
--------------------------------------------------------------------------------
/res/data/mat/group_coherence/group1_Cphd.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/group_coherence/group1_Cphd.mat
--------------------------------------------------------------------------------
/res/data/mat/group_coherence/group2_phd.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/group_coherence/group2_phd.mat
--------------------------------------------------------------------------------
/res/data/mat/load_first.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/load_first.mat
--------------------------------------------------------------------------------
/res/data/mat/load_second.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/load_second.mat
--------------------------------------------------------------------------------
/res/data/mat/noisy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/noisy.mat
--------------------------------------------------------------------------------
/res/data/mat/noisySIN.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/noisySIN.mat
--------------------------------------------------------------------------------
/res/data/mat/noisyyy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/mat/noisyyy.mat
--------------------------------------------------------------------------------
/res/data/npy/1signal_10Hz.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/npy/1signal_10Hz.npy
--------------------------------------------------------------------------------
/res/data/npy/2signals_10Hz.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/npy/2signals_10Hz.npy
--------------------------------------------------------------------------------
/res/data/npy/6signals_10Hz.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/npy/6signals_10Hz.npy
--------------------------------------------------------------------------------
/res/data/npy/fm_square_200Hz.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/npy/fm_square_200Hz.npy
--------------------------------------------------------------------------------
/res/data/npy/freq_mod_200Hz.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/npy/freq_mod_200Hz.npy
--------------------------------------------------------------------------------
/res/data/npy/load_first.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/npy/load_first.npy
--------------------------------------------------------------------------------
/res/data/npy/load_second.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/npy/load_second.npy
--------------------------------------------------------------------------------
/res/data/npy/noisy.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/npy/noisy.npy
--------------------------------------------------------------------------------
/res/data/npy/noisySIN.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/npy/noisySIN.npy
--------------------------------------------------------------------------------
/res/data/npy/noisyyy.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/data/npy/noisyyy.npy
--------------------------------------------------------------------------------
/res/img/physicslogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luphysics/PyMODA/ee648c5ca39f1326a8fb6977f793c407e30e388f/res/img/physicslogo.png
--------------------------------------------------------------------------------
/res/layout/dialog_matlab_runtime.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 342
10 | 273
11 |
12 |
13 |
14 | MATLAB Runtime
15 |
16 |
17 |
18 |
19 |
20 |
21 | 16777215
22 | 16777215
23 |
24 |
25 |
26 | <html><head/><body><p>The MATLAB Runtime was not found. </p><p>Please specify the LD_LIBRARY_PATH using the "runtime" command-line argument, but do not add it to the environment variables. See the documentation for more details.</p><p>If this is message is in error, click "Don't show again". </p></body></html>
27 |
28 |
29 | true
30 |
31 |
32 |
33 |
34 |
35 |
36 | Don't show again
37 |
38 |
39 |
40 |
41 |
42 |
43 | Qt::Horizontal
44 |
45 |
46 | QDialogButtonBox::Ok
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | buttonBox
56 | accepted()
57 | Dialog
58 | accept()
59 |
60 |
61 | 248
62 | 254
63 |
64 |
65 | 157
66 | 274
67 |
68 |
69 |
70 |
71 | buttonBox
72 | rejected()
73 | Dialog
74 | reject()
75 |
76 |
77 | 316
78 | 260
79 |
80 |
81 | 286
82 | 274
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/src/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Table of Contents
4 |
5 | - [src](#src)
6 |
7 |
8 |
9 | ## src
10 |
11 | The `src` folder is the folder containing PyMODA's source code.
12 |
13 | ### main.py
14 |
15 | `main.py` is the entry-point of PyMODA.
16 |
17 | ### Subfolders
18 |
19 | | Subfolder | Contents |
20 | | ----- | ----- |
21 | | `data` | Code related to loading data from files |
22 | | `gui` | Code related to the GUI |
23 | | `maths` | Code related to calculations, e.g. the algorithms used by PyMODA |
24 | | `processes` | Code related to multiprocessing, such as the `Scheduler` class |
25 | | `updater` | Code dedicated to checking for, and applying, updates |
26 | | `utils` | Utility code, e.g. error handling, user settings and command-line argument parsing |
--------------------------------------------------------------------------------
/src/data/parsing/BaseParser.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from abc import ABC, abstractmethod
17 | from typing import List
18 |
19 | from numpy import ndarray
20 |
21 |
22 | class BaseParser(ABC):
23 | """
24 | A base parser. The parser is intended to load data from a file.
25 | """
26 |
27 | def __init__(self, filename: str):
28 | self.filename: str = filename
29 |
30 | @abstractmethod
31 | def parse(self) -> List[ndarray]:
32 | pass
33 |
--------------------------------------------------------------------------------
/src/data/parsing/CsvParser.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import List
17 |
18 | from data.parsing import parsing
19 | from data.parsing.BaseParser import BaseParser
20 |
21 |
22 | class CsvParser(BaseParser):
23 | """
24 | A class which can parse CSV data (comma-separated-values),
25 | either row-wise or column-wise.
26 | """
27 |
28 | def parse(self) -> List[List[float]]:
29 | """
30 | Parses the file, returning a list whose items are a list of
31 | the values in every signal respectively.
32 | """
33 | lines = parsing.get_lines(self.filename)
34 |
35 | if not lines:
36 | return [[]]
37 |
38 | # If each line has more values than the number of lines,
39 | # then each line corresponds to a separate signal.
40 | row_wise = len(lines) < len(lines[0].split(","))
41 | if row_wise:
42 | signal_count = len(lines)
43 | else:
44 | signal_count = len(lines[0].split(","))
45 |
46 | # List containing a list of data for each signal.
47 | data = [[] for _ in range(signal_count)]
48 |
49 | index = 0
50 | for l in lines:
51 | split = l.split(",")
52 |
53 | for i in range(len(split)):
54 | value = float(split[i])
55 | if row_wise:
56 | data[index].append(value)
57 | else:
58 | data[i].append(value)
59 |
60 | if row_wise:
61 | index += 1
62 |
63 | return data
64 |
--------------------------------------------------------------------------------
/src/data/parsing/MatParser.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import List
17 |
18 | from numpy import ndarray
19 | from scipy.io import loadmat
20 |
21 | from data.parsing.BaseParser import BaseParser
22 |
23 |
24 | class MatParser(BaseParser):
25 | """
26 | A parser which loads data from a .mat file.
27 | """
28 |
29 | def parse(self) -> ndarray:
30 | from data.parsing.parsing import ParsingException
31 |
32 | data: dict = loadmat(self.filename)
33 | arrays: List[ndarray] = list(
34 | filter(lambda i: isinstance(i, ndarray), data.values())
35 | )
36 |
37 | if len(arrays) > 1:
38 | raise ParsingException(
39 | ".mat file should contain only one array. To load multiple signals,"
40 | " each signal should be a row or column in the array."
41 | )
42 | elif len(arrays) == 0:
43 | raise ParsingException("No arrays were found in the .mat file.")
44 | else:
45 | signals: ndarray = arrays[0]
46 |
47 | rows, cols = signals.shape
48 | row_wise = rows < cols
49 |
50 | if not row_wise:
51 | signals = signals.T # Transpose signals.
52 |
53 | return signals
54 |
--------------------------------------------------------------------------------
/src/data/parsing/NpyParser.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | import numpy as np
18 | from numpy import ndarray
19 |
20 | from data.parsing.BaseParser import BaseParser
21 |
22 |
23 | class NpyParser(BaseParser):
24 | """
25 | A parser which loads data from a .npy file.
26 | """
27 |
28 | def parse(self) -> ndarray:
29 | signals: ndarray = np.load(self.filename)
30 |
31 | rows, cols = signals.shape
32 | row_wise = rows < cols
33 |
34 | if not row_wise:
35 | signals = signals.T # Transpose signals.
36 |
37 | return signals
38 |
--------------------------------------------------------------------------------
/src/data/parsing/groups/GroupMatParser.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import Dict
17 |
18 | import numpy as np
19 | from numpy import ndarray
20 | from scipy.io import loadmat
21 |
22 | from data.parsing.MatParser import MatParser
23 |
24 |
25 | class GroupMatParser(MatParser):
26 | """
27 | Parser which loads group data from a .mat file.
28 | """
29 |
30 | def parse(self) -> ndarray:
31 | from data.parsing.parsing import ParsingException
32 |
33 | data: Dict = loadmat(self.filename)
34 | arrays = list(filter(lambda i: isinstance(i, ndarray), data.values()))
35 |
36 | if len(arrays) > 1:
37 | raise ParsingException(
38 | f"Data files containing a signal group should only "
39 | f"contain 1 (3-dimensional) array: {self.filename}."
40 | )
41 |
42 | group: ndarray = arrays[0]
43 | x, y, z = group.shape
44 |
45 | if z == 2 and x != 2:
46 | out = np.empty((x, y, z,))
47 | out[0, :, :] = out[:, :, 0]
48 | out[1, :, :] = out[:, :, 1]
49 | else:
50 | out = group
51 |
52 | return out
53 |
--------------------------------------------------------------------------------
/src/data/parsing/groups/GroupNpyParser.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | import numpy as np
18 | from numpy import ndarray
19 |
20 | from data.parsing.BaseParser import BaseParser
21 |
22 |
23 | class GroupNpyParser(BaseParser):
24 | """
25 | A parser which loads group data from a .npy file.
26 | """
27 |
28 | def parse(self) -> ndarray:
29 | group: ndarray = np.load(self.filename)
30 | x, y, z = group.shape
31 |
32 | if z == 2 and x != 2:
33 | out = np.empty((x, y, z,))
34 | out[0, :, :] = out[:, :, 0]
35 | out[1, :, :] = out[:, :, 1]
36 | else:
37 | out = group
38 |
39 | return out
40 |
--------------------------------------------------------------------------------
/src/data/parsing/parsing.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | import os
17 |
18 | from data.parsing.BaseParser import BaseParser
19 | from data.parsing.CsvParser import CsvParser
20 | from data.parsing.MatParser import MatParser
21 | from data.parsing.NpyParser import NpyParser
22 | from data.parsing.groups.GroupMatParser import GroupMatParser
23 | from data.parsing.groups.GroupNpyParser import GroupNpyParser
24 |
25 |
26 | def get_lines(filename):
27 | lines = []
28 | try:
29 | with open(filename, mode="r", encoding="utf-8-sig") as f:
30 | for line in f:
31 | lines.append(line)
32 | except FileNotFoundError:
33 | print(f"File not found at path: '{filename}'")
34 | raise ParsingException(f"File does not exist: {filename}")
35 |
36 | return lines
37 |
38 |
39 | def get_parser(filename, groups=False) -> BaseParser:
40 | """
41 | Gets the appropriate parser for a given file.
42 |
43 | Parameters
44 | ----------
45 | filename : str
46 | The name of the file which will be parsed.
47 | groups : Optional[bool]
48 | (Default = False) Whether the parser is intended to load a signal group, as used by group phase coherence.
49 | """
50 | _, extension = os.path.splitext(filename)
51 | extension = extension.lower()
52 |
53 | if extension == ".mat":
54 | return MatParser(filename) if not groups else GroupMatParser(filename)
55 | elif extension == ".csv" or extension == ".txt":
56 | return CsvParser(filename)
57 | elif extension == ".npy":
58 | return NpyParser(filename) if not groups else GroupNpyParser(filename)
59 |
60 | raise ParsingException(f"Cannot parse a file with the extension: {extension}")
61 |
62 |
63 | class ParsingException(Exception):
64 | """
65 | Exception raised when errors are encountered during parsing.
66 | """
67 |
--------------------------------------------------------------------------------
/src/gui/BaseUI.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | class BaseUI:
19 | """
20 | A base UI element which defines the function 'setup_ui', which is used
21 | to setup UI elements and perform tasks such as inflating the layout from
22 | a .ui file.
23 |
24 | `setup_ui` is called in the constructor.
25 | """
26 |
27 | def __init__(self):
28 | self.setup_ui()
29 |
30 | def setup_ui(self) -> None:
31 | """
32 | A function which should be overridden and used to setup
33 | UI components.
34 | """
35 | pass
36 |
--------------------------------------------------------------------------------
/src/gui/components/DualSignalComponent.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import Tuple
17 |
18 | from gui.plotting.plots.SignalPlot import SignalPlot
19 | from maths.signals.TimeSeries import TimeSeries
20 |
21 |
22 | class DualSignalComponent:
23 | """
24 | Component used in windows which have two signals plotted
25 | simultaneously.
26 | """
27 |
28 | def __init__(self, signal_plot: SignalPlot):
29 | self._signal_plot: SignalPlot = signal_plot
30 |
31 | def plot_signal_pair(self, pair: Tuple[TimeSeries, TimeSeries]):
32 | """Plots a pair of signals on the SignalPlot."""
33 | sig1, sig2 = pair
34 | self._signal_plot.plot(sig1, clear=True)
35 | self._signal_plot.plot(sig2, clear=False)
36 |
--------------------------------------------------------------------------------
/src/gui/components/FreqComponent.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import Optional
17 |
18 | from PyQt5.QtWidgets import QLineEdit
19 |
20 | from utils.decorators import floaty
21 |
22 |
23 | class FreqComponent:
24 | """
25 | A component which handles the 3 frequency-related QLineEdits: fmin, fmax and resolution.
26 | """
27 |
28 | def __init__(
29 | self,
30 | lineedit_fmax: QLineEdit,
31 | lineedit_fmin: QLineEdit,
32 | lineedit_res: QLineEdit,
33 | ):
34 | self._res = lineedit_res
35 | self._fmin = lineedit_fmin
36 | self._fmax = lineedit_fmax
37 |
38 | def get_fmin(self) -> Optional[float]:
39 | fmin, fmax = self.__fmin(), self.__fmax()
40 | if fmin is not None and fmax is not None:
41 | if fmin > fmax:
42 | fmin, fmax = fmax, fmin
43 |
44 | return fmin
45 |
46 | def get_fmax(self) -> Optional[float]:
47 | fmin, fmax = self.__fmin(), self.__fmax()
48 | if fmin is not None and fmax is not None:
49 | if fmin > fmax:
50 | fmin, fmax = fmax, fmin
51 |
52 | return fmax
53 |
54 | @floaty
55 | def __fmin(self) -> Optional[float]:
56 | return self._fmin.text()
57 |
58 | @floaty
59 | def __fmax(self) -> Optional[float]:
60 | return self._fmax.text()
61 |
62 | @floaty
63 | def get_f0(self) -> Optional[float]:
64 | return self._res.text()
65 |
--------------------------------------------------------------------------------
/src/gui/components/PreprocessComponent.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from gui.plotting.plots.PreprocessPlot import PreprocessPlot
17 |
18 |
19 | class PreprocessComponent:
20 | """
21 | Component which handles the plot of the preprocessed signal on a PreprocessPlot.
22 | """
23 |
24 | def __init__(self, preproc_plot: PreprocessPlot):
25 | self._preproc_plot = preproc_plot
26 |
27 | def plot_preprocessed_signal(self, times, signal, preproc_signal):
28 | self._preproc_plot.plot(times, signal, preproc_signal)
29 |
--------------------------------------------------------------------------------
/src/gui/components/SingleSignalComponent.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from gui.plotting.plots.SignalPlot import SignalPlot
17 | from maths.signals.TimeSeries import TimeSeries
18 |
19 |
20 | class SingleSignalComponent:
21 | """
22 | Component used in windows which have a single signal plotted
23 | simultaneously.
24 | """
25 |
26 | def __init__(self, signal_plot: SignalPlot):
27 | self._signal_plot: SignalPlot = signal_plot
28 |
29 | def plot_signal(self, signal: TimeSeries):
30 | """Plots a signal on the SignalPlot."""
31 | self._signal_plot.plot(signal)
32 |
--------------------------------------------------------------------------------
/src/gui/components/VerticalMultiPlotComponent.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5 import sip
17 | from PyQt5.QtWidgets import QVBoxLayout
18 |
19 | from gui.plotting.MatplotlibWidget import MatplotlibWidget
20 |
21 |
22 | class VerticalMultiPlotComponent:
23 | """
24 | Component which handles a vertical layout containing a variable number of plots.
25 | """
26 |
27 | def __init__(self, container: QVBoxLayout):
28 | self._container = container
29 | self._plots = []
30 |
31 | def vplot_remove_plots(self, *plots: MatplotlibWidget):
32 | for plot in plots:
33 | if plot in self._plots:
34 | self._plots.remove(plot)
35 |
36 | if plot is not None:
37 | self._container.removeWidget(plot)
38 | plot.deleteLater()
39 | sip.delete(plot)
40 |
41 | def vplot_remove_all_plots(self):
42 | self.vplot_remove_plots(*self._plots)
43 |
44 | def vplot_insert_widget(self, index, plot):
45 | self._container.insertWidget(index, plot)
46 | self._plots.append(plot)
47 |
48 | def vplot_add_plots(self, *plots):
49 | for plot in plots:
50 | if plot:
51 | self._container.addWidget(plot)
52 | self._plots.append(plot)
53 |
54 | def vplot_get_plot(self, index: int) -> MatplotlibWidget:
55 | return self._plots[index]
56 |
57 | def vplot_count(self) -> int:
58 | return len(self._plots)
59 |
--------------------------------------------------------------------------------
/src/gui/dialogs/ErrorBox.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5.QtWidgets import QMessageBox
17 |
18 |
19 | class ErrorBox(QMessageBox):
20 |
21 | def __init__(self, exc_type, value, traceback):
22 | super().__init__()
23 | self.setIcon(QMessageBox.Warning)
24 | self.setWindowTitle("Error!")
25 | self.setText(f"{value}")
26 |
27 | self.setDetailedText(f"{value}\n{exc_type}\n{traceback}")
28 | self.exec()
29 |
--------------------------------------------------------------------------------
/src/gui/dialogs/MatlabRuntimeDialog.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5 import uic
17 | from PyQt5.QtWidgets import QDialog, QCheckBox
18 |
19 | from data import resources
20 | from gui.BaseUI import BaseUI
21 | from utils.settings import Settings
22 |
23 |
24 | class MatlabRuntimeDialog(QDialog, BaseUI):
25 | def __init__(self):
26 | self.dont_show_again = False
27 | super(MatlabRuntimeDialog, self).__init__()
28 |
29 | def setup_ui(self) -> None:
30 | uic.loadUi(resources.get("layout:dialog_matlab_runtime.ui"), self)
31 |
32 | checkbox: QCheckBox = self.checkbox_dont_show_again
33 | checkbox.stateChanged.connect(self.on_check)
34 |
35 | def on_check(self, state: int):
36 | self.dont_show_again = bool(state)
37 |
--------------------------------------------------------------------------------
/src/gui/dialogs/UseShortcutComponent.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import Callable
17 |
18 | from PyQt5.QtCore import QObject
19 | from PyQt5.QtGui import QKeySequence
20 | from PyQt5.QtWidgets import QShortcut
21 |
22 |
23 | class UseShortcutComponent:
24 | def __init__(
25 | self, parent: QObject, on_shortcut_activated: Callable, *args, **kwargs
26 | ):
27 | super(UseShortcutComponent, self).__init__(*args, **kwargs)
28 |
29 | self.shortcut = QShortcut(QKeySequence("Ctrl+U"), parent)
30 | self.shortcut.activated.connect(on_shortcut_activated)
31 |
--------------------------------------------------------------------------------
/src/gui/dialogs/files/DragDropLabel.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import Callable
17 |
18 | from PyQt5 import QtGui
19 | from PyQt5.QtGui import QDropEvent
20 | from PyQt5.QtWidgets import QLabel
21 |
22 |
23 | class DragDropLabel(QLabel):
24 | """
25 | A label which accepts drag-and-drop events for files. When a drop
26 | succeeds, the filename is shown in the label. The label changes
27 | colour while a drag event is in progress.
28 | """
29 |
30 | def __init__(self, parent):
31 | self.drop_callback: Callable = None
32 | super().__init__(parent)
33 |
34 | def dropEvent(self, event: QDropEvent) -> None:
35 | """Called when a drop event occurs."""
36 | file_path = event.mimeData().text().rstrip()
37 | if self.drop_callback:
38 | self.drop_callback(file_path)
39 |
40 | self.show_selected_file(file_path)
41 |
42 | def show_selected_file(self, file_path) -> None:
43 | file_name = file_path.split("/")[-1].split("\\")[-1]
44 | self.setText(f"File selected:\n{file_name}")
45 | self.set_background(highlighted=False)
46 |
47 | def dragLeaveEvent(self, e: QtGui.QDragLeaveEvent) -> None:
48 | self.set_background(highlighted=False)
49 |
50 | def set_background(self, highlighted: bool) -> None:
51 | background = "grey" if highlighted else "transparent"
52 | self.setStyleSheet(
53 | f"QLabel {{ background-color : {background}; color : black; }}"
54 | )
55 |
56 | def dragEnterEvent(self, event: QtGui.QDragEnterEvent) -> None:
57 | """Called when a drag event enters the label."""
58 | if event.mimeData().hasText():
59 | event.accept()
60 | self.set_background(highlighted=True)
61 | else:
62 | event.ignore()
63 |
64 | def set_drop_callback(self, callback: Callable[[str], None]) -> None:
65 | """Sets a callback for when the drop is complete."""
66 | self.drop_callback = callback
67 |
--------------------------------------------------------------------------------
/src/gui/plotting/PlotWidget.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5.QtWidgets import QWidget
17 |
18 | from gui.BaseUI import BaseUI
19 |
20 |
21 | class PlotWidget(QWidget, BaseUI):
22 | """
23 | A base component for plotting. Should be independent of any
24 | plotting library.
25 | """
26 |
27 | def get_xlabel(self) -> str:
28 | """Returns the label for the x-axis. Should be overridden in subclasses."""
29 | pass
30 |
31 | def get_ylabel(self) -> str:
32 | """Returns the label for the y-axis. Should be overridden in subclasses."""
33 | pass
34 |
35 | def set_in_progress(self, in_progress) -> None:
36 | """Sets the progress bar to display whether the plotting is in progress."""
37 | pass
38 |
39 | def on_plot_complete(self) -> None:
40 | """
41 | Should be called after the first plotting is complete. It will then set the initial state
42 | so that the reset button can work.
43 | """
44 | pass
45 |
46 | def clear(self) -> None:
47 | """
48 | Clears the plot, removing all plotted elements.
49 | """
50 | pass
51 |
52 | def update_xlabel(self, text=None) -> None:
53 | """
54 | Updates the x-label. If no value is passed,
55 | the result from get_xlabel() will be used.
56 | """
57 | pass
58 |
59 | def update_ylabel(self, text=None) -> None:
60 | """
61 | Updates the y-label. If no value is passed,
62 | the result from get_ylabel() will be used.
63 | """
64 | pass
65 |
--------------------------------------------------------------------------------
/src/gui/plotting/PyQtGraphWidget.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5.QtWidgets import QVBoxLayout
17 | from pyqtgraph.opengl import GLViewWidget
18 |
19 | from gui.plotting.PlotWidget import PlotWidget
20 |
21 |
22 | class PyQtGraphWidget(PlotWidget):
23 | """
24 | A widget which enables plotting via PyQtGraph.
25 |
26 | Warning: not fully implemented. Complete implementation is
27 | not currently planned.
28 | """
29 |
30 | def setup_ui(self) -> None:
31 | self.layout = QVBoxLayout(self)
32 |
33 | self.plot_widget = GLViewWidget()
34 | self.layout.addWidget(self.plot_widget)
35 |
--------------------------------------------------------------------------------
/src/gui/plotting/plots/AmplitudePlot.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from gui.plotting.MatplotlibWidget import MatplotlibWidget
17 |
18 |
19 | class AmplitudePlot(MatplotlibWidget):
20 |
21 | def __init__(self, parent):
22 | self.ylabel = "Frequency (Hz)"
23 | self.xlabel = ""
24 | super(AmplitudePlot, self).__init__(parent)
25 |
26 | def plot(self, amplitude, freq, surrogates=None):
27 | self.clear()
28 |
29 | self.update_ylabel()
30 | self.update_xlabel()
31 |
32 | self.axes.yaxis.set_label_position("right")
33 |
34 | y = freq
35 | ylim = sorted([y[0], y[-1]])
36 | self.axes.set_ylim(ylim)
37 |
38 | self.axes.plot(amplitude, freq)
39 | if hasattr(surrogates, "__len__") and len(surrogates) == len(amplitude):
40 | self.axes.plot(surrogates, freq)
41 | self.axes.legend(["Original signal", "Surrogate"])
42 |
43 | self.apply_scale()
44 | self.axes.autoscale(False)
45 | self.on_plot_complete()
46 |
47 | def get_ylabel(self):
48 | return self.ylabel
49 |
50 | def get_xlabel(self):
51 | return self.xlabel
52 |
53 | def set_xlabel(self, text):
54 | self.xlabel = text
55 |
56 | def set_ylabel(self, text):
57 | self.ylabel = text
58 |
--------------------------------------------------------------------------------
/src/gui/plotting/plots/GroupCoherencePlot.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | import numpy as np
17 |
18 | from gui.plotting.MatplotlibWidget import MatplotlibWidget
19 |
20 |
21 | class GroupCoherencePlot(MatplotlibWidget):
22 | def __init__(self, parent):
23 | self.xlabel = "Frequency (Hz)"
24 | self.ylabel = "Coherence"
25 | super(GroupCoherencePlot, self).__init__(parent)
26 |
27 | def plot(self, freq, coh1, coh2, average="median", percentile: float = 75):
28 | self.clear()
29 |
30 | if percentile is None or percentile > 100:
31 | return
32 |
33 | self.update_ylabel()
34 | self.update_xlabel()
35 |
36 | single = coh2 is None
37 | if average == "median":
38 | favg = np.nanmedian
39 | average = "Median"
40 | else:
41 | favg = np.nanmean
42 | average = "Mean"
43 |
44 | pc11 = np.nanpercentile(coh1, 100 - percentile, axis=0)
45 | pc12 = np.nanpercentile(coh1, percentile, axis=0)
46 |
47 | if not single:
48 | pc21 = np.nanpercentile(coh2, 100 - percentile, axis=0)
49 | pc22 = np.nanpercentile(coh2, percentile, axis=0)
50 |
51 | color1 = "black"
52 | color2 = "red"
53 | alpha = 0.1
54 | linewidth = 1.1
55 |
56 | self.axes.plot(freq, favg(coh1, axis=0), color=color1, linewidth=linewidth)
57 | self.axes.fill_between(freq, pc11, pc12, color=color1, alpha=alpha)
58 |
59 | legend = [
60 | f"{average} coherence (group 1)",
61 | ]
62 |
63 | if not single:
64 | self.axes.plot(freq, favg(coh2, axis=0), color=color2, linewidth=linewidth)
65 | self.axes.fill_between(freq, pc21, pc22, color=color2, alpha=alpha)
66 | legend.append(legend[0].replace("1", "2"))
67 |
68 | self.set_log_scale(True, "x")
69 | self.axes.legend(legend)
70 |
71 | self.apply_scale()
72 | self.axes.autoscale(False)
73 | self.on_plot_complete()
74 |
75 | def get_ylabel(self):
76 | return self.ylabel
77 |
78 | def get_xlabel(self):
79 | return self.xlabel
80 |
81 | def set_xlabel(self, text):
82 | self.xlabel = text
83 |
84 | def set_ylabel(self, text):
85 | self.ylabel = text
86 |
--------------------------------------------------------------------------------
/src/gui/plotting/plots/PreprocessPlot.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | import numpy as np
17 |
18 | from gui.plotting.MatplotlibWidget import MatplotlibWidget
19 |
20 |
21 | class PreprocessPlot(MatplotlibWidget):
22 |
23 | def plot(self, times: np.ndarray, original: np.ndarray, preprocessed: np.ndarray):
24 | self.clear()
25 | self.rect_stack.clear()
26 |
27 | self.axes.autoscale(True)
28 |
29 | width = 0.7
30 | self.axes.plot(times, original, linewidth=width)
31 | self.axes.plot(times, preprocessed, linewidth=width)
32 |
33 | self.axes.legend(["Original", "Preprocessed"])
34 |
35 | xlim = sorted((times[0], times[-1],))
36 | self.axes.set_xlim(xlim)
37 |
38 | self.axes.autoscale(False)
39 | self.on_plot_complete()
40 |
--------------------------------------------------------------------------------
/src/gui/plotting/plots/Rect.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | class Rect:
19 | """
20 | A simple class representing the coordinates of a rectangle
21 | that is drawn in matplotlib. (x1,y1) refer to the upper left
22 | corner, while (x2,y2) are the lower right corner.
23 | """
24 |
25 | def __init__(self, x1, y1, x2=None, y2=None):
26 | self.x1 = x1
27 | self.x2 = x2
28 | self.y1 = y1
29 | self.y2 = y2
30 |
31 | def set_corner(self, x2, y2):
32 | """
33 | Sets the coordinates of the "bottom right" corner;
34 | however, note that the corner can be in any location.
35 | """
36 | self.x2 = x2
37 | self.y2 = y2
38 |
39 | def sorted(self):
40 | """
41 | Returns a new Rect instance which is sorted so that the
42 | corner (x1, y1) is in the upper left and the corner
43 | (x2, y2) is in the lower right.
44 |
45 | If the current instance does not contain all four coordinates,
46 | returns the current instance. Does not affect the current instance.
47 | """
48 | if not self.is_valid():
49 | return self
50 |
51 | x1 = self.x1
52 | x2 = self.x2
53 | y1 = self.y1
54 | y2 = self.y2
55 |
56 | if x2 < x1:
57 | x1, x2 = x2, x1 # Swap values.
58 |
59 | if y2 < y1:
60 | y1, y2 = y2, y1 # Swap values.
61 |
62 | return Rect(x1, y1, x2, y2)
63 |
64 | def get_width(self):
65 | return self.x2 - self.x1
66 |
67 | def get_height(self):
68 | return self.y2 - self.y1
69 |
70 | def is_valid(self):
71 | """
72 | Returns whether this is a Rect with both corners defined.
73 | Not affected by whether the corners are correctly sorted or not.
74 | """
75 | return self.x2 is not None and self.y2 is not None
76 |
77 | def __str__(self) -> str:
78 | return f"{self.x1}, {self.y1}; {self.x2}, {self.y2}"
79 |
--------------------------------------------------------------------------------
/src/gui/plotting/plots/SignalPlot.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | from numpy import ndarray
18 |
19 | from gui.plotting.MatplotlibWidget import MatplotlibWidget
20 | from maths.signals.TimeSeries import TimeSeries
21 |
22 |
23 | class SignalPlot(MatplotlibWidget):
24 | """
25 | Plots the signal, which is a simple set of amplitudes against time.
26 | """
27 |
28 | def __init__(self, parent):
29 | MatplotlibWidget.__init__(self, parent)
30 | self.toolbar.disable_panning()
31 |
32 | def plotxy(self, x: ndarray, y: ndarray, clear: bool = True) -> None:
33 | if clear:
34 | self.clear()
35 | self.rect_stack.clear()
36 |
37 | self.axes.xaxis.set_label_position("top")
38 | self.update_xlabel()
39 | self.update_ylabel()
40 | self.axes.autoscale(True)
41 |
42 | if len(x.shape) <= 1:
43 | xlim = (x[0], x[-1])
44 | else:
45 | xlim = (x[0, 0], x[0, -1])
46 |
47 | self.axes.plot(x, y, linewidth=0.7)
48 | self.axes.autoscale(False)
49 | self.axes.set_xlim(xlim)
50 | self.on_plot_complete()
51 |
52 | def plot(self, data: TimeSeries, clear: bool = True) -> None:
53 | x = data.times
54 | y = data.signal
55 |
56 | self.plotxy(x, y, clear=clear)
57 |
58 | def zoom_to(self, rect, save_state=True, trigger_listeners=True) -> None:
59 | """Override the zoom to not change the range of visible y-values."""
60 | rect.y1, rect.y2 = self.ylim()
61 | super(SignalPlot, self).zoom_to(rect, save_state, trigger_listeners)
62 |
63 | def get_xlabel(self) -> str:
64 | return "Time (s)"
65 |
66 | def get_ylabel(self) -> str:
67 | return "Value"
68 |
--------------------------------------------------------------------------------
/src/gui/windows/BaseWindow.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5 import QtGui
17 | from PyQt5.QtGui import QIcon
18 | from PyQt5.QtWidgets import QMainWindow
19 |
20 | from data import resources
21 | from gui.BaseUI import BaseUI
22 |
23 |
24 | class BaseWindow(QMainWindow, BaseUI):
25 | """
26 | A base window which inherits from BaseUI.
27 | """
28 |
29 | def __init__(self, application):
30 | self.application = application
31 |
32 | super(BaseWindow, self).__init__()
33 | self.update_title()
34 | self.set_icon()
35 |
36 | def update_title(self, title=resources.get_program_name()):
37 | """
38 | Sets the title of the window. If no title is supplied,
39 | the default name of the application is used.
40 | """
41 | self.setWindowTitle(title)
42 |
43 | def set_icon(self, img=resources.get("image:icon.svg")):
44 | icon = QIcon(img)
45 | self.setWindowIcon(icon)
46 |
47 | def closeEvent(self, e: QtGui.QCloseEvent) -> None:
48 | try:
49 | self.application.notify_close_event(self)
50 | except AttributeError:
51 | pass
52 | super(BaseWindow, self).closeEvent(e)
53 |
--------------------------------------------------------------------------------
/src/gui/windows/CentredWindow.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | from PyQt5.QtWidgets import QDesktopWidget
18 |
19 | from gui.windows.BaseWindow import BaseWindow
20 |
21 |
22 | class CentredWindow(BaseWindow):
23 | """
24 | A window which opens at the centre of the screen.
25 | """
26 |
27 | def __init__(self, application):
28 | super(CentredWindow, self).__init__(application)
29 | self.centre()
30 |
31 | def centre(self):
32 | """Moves the window to the centre of the screen."""
33 | geometry = self.frameGeometry()
34 | centre = QDesktopWidget().availableGeometry().center()
35 | geometry.moveCenter(centre)
36 | self.move(geometry.topLeft())
37 |
--------------------------------------------------------------------------------
/src/gui/windows/MaximisedWindow.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from gui.windows.CentredWindow import CentredWindow
17 | from utils import args
18 |
19 |
20 | class MaximisedWindow(CentredWindow):
21 | """
22 | A window which is maximised when it opens, unless overridden
23 | by a command-line argument.
24 | """
25 |
26 | def __init__(self, application):
27 | super().__init__(application)
28 | if args.maximise():
29 | self.showMaximized()
30 |
--------------------------------------------------------------------------------
/src/gui/windows/ViewProperties.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | class ViewProperties:
19 | """
20 | A class which should be overridden to declare the variables which
21 | will be added when the .ui file is inflated to create a window.
22 |
23 | The only purpose of this class is to provide useful code
24 | completion in the IDE.
25 |
26 | All variables should be initialised as None in the constructor
27 | and marked with appropriate type annotations.
28 |
29 | Important: The constructor for a ViewProperties class should be called
30 | before the .ui file is inflated.
31 | """
32 |
--------------------------------------------------------------------------------
/src/gui/windows/bayesian/DBPlot.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from gui.plotting.MatplotlibWidget import MatplotlibWidget
17 |
18 |
19 | class DBPlot(MatplotlibWidget):
20 | def plot(self, times, values, *args, **kwargs):
21 | self.update_xlabel()
22 | self.update_ylabel()
23 |
24 | self.axes.autoscale(True)
25 |
26 | self.axes.plot(times, values, linewidth=0.8, *args, **kwargs)
27 | self.axes.autoscale(False)
28 | self.axes.set_xlim([times[0], times[-1]])
29 | self.on_plot_complete()
30 |
31 | def get_xlabel(self):
32 | return "Time (s)"
33 |
--------------------------------------------------------------------------------
/src/gui/windows/bayesian/DBPlot3d.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from gui.plotting.MatplotlibWidget import MatplotlibWidget
17 | from gui.plotting.plots.ColorMeshPlot import colormap
18 |
19 |
20 | class DBPlot3d(MatplotlibWidget):
21 | def plot(self, x, y, z):
22 | self.axes.xaxis.set_label_position("top")
23 | self.axes.autoscale(True)
24 |
25 | self.axes.plot_surface(x, y, z, cmap=colormap())
26 | self.axes.autoscale(False)
27 |
28 | self.axes.invert_xaxis()
29 | self.set_mouse_zoom_enabled(False)
30 |
31 | self.on_plot_complete()
32 |
33 | def is_3d(self) -> bool:
34 | return True
35 |
--------------------------------------------------------------------------------
/src/gui/windows/bayesian/ParamSet.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import Tuple
17 |
18 |
19 | class ParamSet:
20 | """
21 | Represents the parameter set used by the dynamical Bayesian inference window.
22 | """
23 |
24 | def __init__(
25 | self,
26 | freq_range1: Tuple[float, float],
27 | freq_range2: Tuple[float, float],
28 | window: float,
29 | propagation_const: float,
30 | surr_count: int,
31 | overlap: float,
32 | order: int,
33 | confidence_level: float,
34 | ):
35 | self.freq_range1 = freq_range1
36 | self.freq_range2 = freq_range2
37 | self.window = window
38 | self.propagation_const = propagation_const
39 | self.surr_count = surr_count
40 | self.overlap = overlap
41 | self.order = order
42 | self.confidence_level = confidence_level
43 |
44 | def to_string(self) -> Tuple[str, str]:
45 | """
46 | Returns a string representation of this object for each frequency band.
47 | """
48 | # Function to use for each frequency band.
49 | def convert(freq: Tuple[float, float]) -> str:
50 | freq_range_str = ",".join([str(i) for i in freq])
51 | items = [
52 | freq_range_str,
53 | self.window,
54 | self.overlap,
55 | self.propagation_const,
56 | self.order,
57 | self.surr_count,
58 | self.confidence_level,
59 | ]
60 |
61 | return " | ".join([str(i) for i in items])
62 |
63 | return convert(self.freq_range1), convert(self.freq_range2)
64 |
--------------------------------------------------------------------------------
/src/gui/windows/bispectrum/BAPlot.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from numpy import ndarray
17 |
18 | from gui.plotting.MatplotlibWidget import MatplotlibWidget
19 |
20 |
21 | class BAPlot(MatplotlibWidget):
22 |
23 | def plot(self, x: ndarray, y: ndarray):
24 | self.clear()
25 |
26 | self.update_xlabel()
27 | self.update_ylabel()
28 |
29 | self.axes.autoscale(True)
30 |
31 | self.axes.plot(x, y, linewidth=0.8)
32 | self.axes.autoscale(False)
33 | self.axes.set_xlim([x[0], x[-1]])
34 | self.on_plot_complete()
35 |
--------------------------------------------------------------------------------
/src/gui/windows/bispectrum/BAViewProperties.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5.QtWidgets import (
17 | QLineEdit,
18 | QSlider,
19 | QComboBox,
20 | QVBoxLayout,
21 | QGridLayout,
22 | QPushButton,
23 | QListWidget,
24 | QCheckBox,
25 | QRadioButton,
26 | )
27 |
28 | from gui.plotting.plots.AmplitudePlot import AmplitudePlot
29 | from gui.plotting.plots.ColorMeshPlot import ColorMeshPlot
30 | from gui.windows.ViewProperties import ViewProperties
31 | from gui.windows.bispectrum.BAPlot import BAPlot
32 |
33 |
34 | class BAViewProperties(ViewProperties):
35 | def __init__(self):
36 | """Define properties introduced by the .ui file."""
37 | self.line_surrogate: QLineEdit = None
38 | self.slider_surrogate: QSlider = None
39 |
40 | self.lineedit_alpha: QLineEdit = None
41 | self.lineedit_nv: QLineEdit = None
42 | self.lineedit_freq_x: QLineEdit = None
43 | self.lineedit_freq_y: QLineEdit = None
44 |
45 | self.combo_plot_type: QComboBox = None
46 |
47 | self.grid_main: QGridLayout = None
48 | self.vbox_left: QVBoxLayout = None
49 | self.vbox_right: QVBoxLayout = None
50 |
51 | self.plot_right_bottom: BAPlot = None
52 | self.plot_right_middle: BAPlot = None
53 |
54 | self.plot_right_top: AmplitudePlot = None # Plots amplitude for WT.
55 | self.plot_main: ColorMeshPlot = None # Plots WT or bispectrum.
56 |
57 | self.btn_add_point: QPushButton = None
58 | self.btn_select_point: QPushButton = None
59 | self.btn_clear_plots: QPushButton = None
60 |
61 | self.listwidget_freq: QListWidget = None
62 | self.checkbox_plot_surr: QCheckBox = None
63 |
64 | self.radio_power: QRadioButton = None
65 | self.radio_ampl: QRadioButton = None
66 |
--------------------------------------------------------------------------------
/src/gui/windows/common/BaseTFViewProperties.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5.QtWidgets import QPushButton
17 |
18 | from PyQt5.QtWidgets import QLineEdit, QListWidget, QMenuBar
19 |
20 | from gui.windows.ViewProperties import ViewProperties
21 | from gui.plotting.plots.PreprocessPlot import PreprocessPlot
22 |
23 |
24 | class BaseTFViewProperties(ViewProperties):
25 |
26 | def __init__(self):
27 | self.btn_calculate_single: QPushButton = None
28 | self.btn_calculate_all: QPushButton = None
29 |
30 | # The menu bar at the top of the window.
31 | self.menubar: QMenuBar = None
32 |
33 | # The QLineEdits for frequencies.
34 | self.line_fmin: QLineEdit = None
35 | self.line_fmax: QLineEdit = None
36 | self.line_res: QLineEdit = None
37 |
38 | # The QListWidget which contains the names of different signals.
39 | self.list_select_data: QListWidget = None
40 |
--------------------------------------------------------------------------------
/src/gui/windows/groupcoherence/GCViewProperties.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5.QtWidgets import QLineEdit, QPushButton, QListWidget, QGroupBox
17 |
18 | from gui.windows.ViewProperties import ViewProperties
19 |
20 |
21 | class GCViewProperties(ViewProperties):
22 | def __init__(self):
23 | self.line_stat_fmin: QLineEdit = None
24 | self.line_stat_fmax: QLineEdit = None
25 |
26 | self.btn_stat_add: QPushButton = None
27 | self.btn_stat_del: QPushButton = None
28 |
29 | self.btn_stat_calc: QPushButton = None
30 |
31 | self.list_stat: QListWidget = None
32 | self.groupbox_stats: QGroupBox = None
33 |
34 | self.line_percentile: QLineEdit = None
35 | self.line_plot_percentile: QLineEdit = None
36 |
--------------------------------------------------------------------------------
/src/gui/windows/harmonics/DHViewProperties.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5.QtWidgets import QComboBox, QLineEdit
17 |
18 | from gui.windows.ViewProperties import ViewProperties
19 |
20 |
21 | class DHViewProperties(ViewProperties):
22 | def __init__(self):
23 | self.combo_plot_type: QComboBox = None
24 |
25 | self.line_sigma: QLineEdit = None
26 | self.line_res: QLineEdit = None
27 | self.line_fmax: QLineEdit = None
28 | self.line_fmin: QLineEdit = None
29 |
--------------------------------------------------------------------------------
/src/gui/windows/phasecoherence/PCViewProperties.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5.QtWidgets import QSlider, QLineEdit
17 |
18 | from gui.windows.ViewProperties import ViewProperties
19 |
20 |
21 | class PCViewProperties(ViewProperties):
22 |
23 | def __init__(self):
24 | self.slider_surrogate: QSlider = None
25 | self.line_surrogate: QLineEdit = None
26 |
--------------------------------------------------------------------------------
/src/gui/windows/ridgeextraction/REPlot.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from gui.plotting.MatplotlibWidget import MatplotlibWidget
17 |
18 |
19 | class REPlot(MatplotlibWidget):
20 |
21 | def plot(self, times, values):
22 | self.axes.xaxis.set_label_position("top")
23 | self.update_xlabel()
24 | self.update_ylabel()
25 |
26 | self.axes.autoscale(True)
27 |
28 | self.axes.plot(times, values, linewidth=0.8)
29 | self.axes.autoscale(False)
30 | self.axes.set_xlim([times[0], times[-1]])
31 | self.on_plot_complete()
32 |
33 | def get_xlabel(self):
34 | return "Time (s)"
35 |
--------------------------------------------------------------------------------
/src/gui/windows/ridgeextraction/REViewProperties.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5.QtWidgets import QPushButton, QLineEdit, QListWidget
17 |
18 | from gui.windows.ViewProperties import ViewProperties
19 | from gui.windows.ridgeextraction.REPlot import REPlot
20 |
21 |
22 | class REViewProperties(ViewProperties):
23 |
24 | def __init__(self):
25 | # The top and bottom REPlots.
26 | self.re_top: REPlot = None
27 | self.re_bottom: REPlot = None
28 |
29 | self.btn_add_region: QPushButton = None
30 | self.btn_mark_region: QPushButton = None
31 |
32 | self.btn_filter: QPushButton = None
33 | self.btn_ridges: QPushButton = None
34 |
35 | self.line_freq1: QLineEdit = None
36 | self.line_freq2: QLineEdit = None
37 |
38 | self.list_intervals: QListWidget = None
39 |
--------------------------------------------------------------------------------
/src/gui/windows/timefrequency/TFViewProperties.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5.QtWidgets import QRadioButton, QComboBox
17 |
18 | from gui.plotting.plots.PreprocessPlot import PreprocessPlot
19 | from gui.windows.ViewProperties import ViewProperties
20 |
21 |
22 | class TFViewProperties(ViewProperties):
23 | def __init__(self):
24 | self.radio_transform_wt: QRadioButton = None
25 | self.plot_preproc: PreprocessPlot = None
26 |
27 | self.combo_impl: QComboBox = None
28 |
--------------------------------------------------------------------------------
/src/main.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | """
17 | The entry-point of PyMODA.
18 | """
19 |
20 | __version__ = "0.8.2"
21 |
22 | import asyncio
23 | import multiprocessing
24 | import os
25 | import signal
26 | import sys
27 | from os import path
28 | from pathlib import Path
29 |
30 | import multiprocess
31 | import qasync
32 |
33 | import utils
34 | from gui.Application import Application
35 | from processes import mp_utils
36 | from utils import errorhandling, stdout_redirect, args, log_utils, launcher
37 |
38 | if __name__ == "__main__":
39 | # Fix issues when packaged with PyInstaller.
40 | for m in (multiprocess, multiprocessing):
41 | m.freeze_support()
42 |
43 | # If not started via the launcher, exit and run new instance via launcher.
44 | if utils.is_frozen and not args.launcher() and launcher.is_launcher_present():
45 | launcher.start_via_launcher()
46 | sys.exit(0)
47 |
48 | # Choose the desired working directory.
49 | if utils.is_frozen:
50 | # When packaged with PyInstaller, use the directory containing the executable.
51 | location = os.path.abspath(sys._MEIPASS)
52 | else:
53 | # When running as a normal Python program, use the root of the repository.
54 | location = Path(path.abspath(path.dirname(__file__))).parent
55 |
56 | # Set the working directory for consistency.
57 | os.chdir(location)
58 |
59 | # Fix Ctrl-C behaviour with PyQt.
60 | signal.signal(signal.SIGINT, signal.SIG_DFL)
61 |
62 | args.init()
63 | log_utils.init()
64 | errorhandling.init()
65 | stdout_redirect.init()
66 |
67 | app = Application(sys.argv)
68 |
69 | # Setup asyncio to work with PyQt.
70 | loop = qasync.QEventLoop(app)
71 | asyncio.set_event_loop(loop)
72 |
73 | # Fix multiprocessing on macOS.
74 | mp_utils.set_mp_start_method()
75 |
76 | # Open the launcher window. Must be called after setting the event loop.
77 | app.start_launcher()
78 |
79 | with loop:
80 | sys.exit(loop.run_forever())
81 |
--------------------------------------------------------------------------------
/src/maths/algorithms/matlabwrappers/bayesian_inference.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | from multiprocess import Queue
18 |
19 | from gui.windows.bayesian.ParamSet import ParamSet
20 | from maths.signals.TimeSeries import TimeSeries
21 |
22 |
23 | def _moda_dynamic_bayesian_inference(
24 | queue: Queue, signal1: TimeSeries, signal2: TimeSeries, params: ParamSet
25 | ):
26 | """
27 | UNUSED.
28 |
29 | Uses the MATLAB-packaged function to perform Bayesian inference.
30 | Unused because it causes a serious error on Linux. Check the Python implementation
31 | of Bayesian inference instead (`bayesian.py`).
32 | """
33 | import full_bayesian
34 | import matlab
35 |
36 | package = full_bayesian.initialize()
37 |
38 | sig1 = matlab.double(signal1.signal.tolist())
39 | sig2 = matlab.double(signal2.signal.tolist())
40 |
41 | int1 = list(params.freq_range1)
42 | int2 = list(params.freq_range2)
43 |
44 | fs = signal1.frequency
45 | win = params.window
46 | pr = params.propagation_const
47 | ovr = params.overlap
48 | bn = params.order
49 | ns = params.surr_count
50 | signif = params.confidence_level
51 |
52 | result = package.full_bayesian(
53 | sig1, sig2, *int1, *int2, fs, win, pr, ovr, bn, ns, signif
54 | )
55 |
56 | queue.put((signal1.name, *result))
57 |
--------------------------------------------------------------------------------
/src/maths/algorithms/matlabwrappers/biphase_wav_new.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | """
18 | Do not import this module in the main process, or it will break Linux support
19 | due to issues with the LD_LIBRARY_PATH.
20 | """
21 | from typing import Tuple
22 |
23 | from numpy import ndarray
24 | from pymodalib.utils.decorators import matlabwrapper
25 |
26 | from maths.num_utils import matlab_to_numpy
27 |
28 |
29 | @matlabwrapper(module="biphaseWavNew")
30 | def calculate(
31 | signal1: ndarray, signal2: ndarray, fs, f0, fr, opt: dict
32 | ) -> Tuple[ndarray, ndarray]:
33 | """
34 | Calculates the biphase and biamplitude from the bispectrum using the MATLAB-packaged function.
35 | """
36 | import biphaseWavPython
37 | import matlab
38 |
39 | package = biphaseWavPython.initialize()
40 |
41 | result = package.biphaseWavPython(
42 | matlab.double(signal1),
43 | matlab.double(signal2),
44 | fs,
45 | f0,
46 | matlab.double(list(fr)),
47 | opt,
48 | nargout=2,
49 | )
50 |
51 | biamp, biphase = result
52 |
53 | biamp = matlab_to_numpy(biamp)
54 | biphase = matlab_to_numpy(biphase)
55 |
56 | return biamp, biphase
57 |
58 |
59 | def expand(_dict: dict) -> tuple:
60 | """
61 | Expands a dictionary into a MATLAB-friendly list of arguments.
62 | For example, {"fmin": 5, "f0": 1} expands to ("fmin", 5, "f0", 1).
63 | """
64 | _list = []
65 | for key, value in _dict.items():
66 | _list.append(key)
67 | _list.append(value)
68 |
69 | return tuple(_list)
70 |
--------------------------------------------------------------------------------
/src/maths/algorithms/matlabwrappers/bispec_wav_new.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | from typing import Tuple
18 |
19 | import numpy as np
20 | from numpy import ndarray
21 | from pymodalib.utils.decorators import matlabwrapper
22 |
23 | from maths.num_utils import multi_matlab_to_numpy
24 |
25 |
26 | @matlabwrapper(module="bispecWavPython")
27 | def calculate(
28 | signal1: ndarray, signal2: ndarray, fs, params: dict
29 | ) -> Tuple[ndarray, ndarray, ndarray, ndarray, dict]:
30 | """
31 | Calculates the bispectrum of 2 signals using the MATLAB-packaged function.
32 | """
33 | import bispecWavPython
34 | import matlab
35 |
36 | package = bispecWavPython.initialize()
37 |
38 | result = package.bispecWavPython(
39 | matlab.double(signal1), matlab.double(signal2), fs, *expand(params), nargout=5
40 | )
41 |
42 | bisp, freq, wt1, wt2, opt = result
43 | bisp, freq, wt1, wt2 = multi_matlab_to_numpy(bisp, freq, wt1, wt2)
44 |
45 | opt["PadLR1"], opt["PadLR2"], opt["twf1"], opt["twf2"] = [
46 | n.tolist()[0]
47 | for n in multi_matlab_to_numpy(
48 | opt["PadLR1"], opt["PadLR2"], opt["twf1"], opt["twf2"]
49 | )
50 | ]
51 |
52 | output = (np.abs(bisp), freq, np.abs(wt1), np.abs(wt2), opt)
53 | return output
54 |
55 |
56 | def expand(_dict: dict) -> tuple:
57 | """
58 | Expands a dictionary into a MATLAB-friendly list of arguments.
59 | For example, {"fmin": 5, "f0": 1} expands to ("fmin", 5, "f0", 1).
60 | """
61 | _list = []
62 | for key, value in _dict.items():
63 | _list.append(key)
64 | _list.append(value)
65 |
66 | return tuple(_list)
67 |
--------------------------------------------------------------------------------
/src/maths/algorithms/matlabwrappers/wav_surrogate.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | from numpy import ndarray
18 |
19 |
20 | def calculate(signal: ndarray, surr_type: str, adj: int) -> ndarray:
21 | """
22 | Calculates surrogates using the MATLAB-packaged function. Used in bispectrum analysis for
23 | IAAFT2 surrogates.
24 |
25 | :param signal: the signal
26 | :param surr_type: the type of surrogate
27 | :param adj: ?
28 | :return: [1D array] the surrogate signal
29 | """
30 | import matlab
31 | import wavsurrogate
32 |
33 | package = wavsurrogate.initialize()
34 |
35 | if isinstance(signal, ndarray):
36 | signal = signal.tolist()
37 |
38 | result = package.wavsurrogate(matlab.double(signal), surr_type, adj)
39 |
40 | return result
41 |
--------------------------------------------------------------------------------
/src/maths/algorithms/matlabwrappers/wft.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | from maths.params.TFParams import TFParams, _f0, _fmin
19 | from maths.signals.TimeSeries import TimeSeries
20 |
21 |
22 | def calculate(time_series: TimeSeries, params: TFParams):
23 | """
24 | Calculates the windowed Fourier transform using the MATLAB-packaged function.
25 |
26 | :param time_series: the signal to perform the transform on
27 | :param params: the params object containing parameters to pass to the MATLAB function
28 | :return: [2D array] the windowed Fourier transform; [1D array] the frequencies
29 | """
30 |
31 | import WFT
32 | import matlab
33 |
34 | package = WFT.initialize()
35 |
36 | signal_matlab = matlab.double([time_series.signal.tolist()])
37 |
38 | """
39 | The value passed for 'f0' should actually be that of 'fr' in the case
40 | of WFT. In the Matlab version this is handled before passing the value
41 | to the function, so we'll do the same.
42 |
43 | When the value has been left blank, there is no problem because this
44 | case is handled by the Matlab function.
45 | """
46 | params_dict = params.get()
47 |
48 | f0 = params_dict.get(_f0)
49 | fmin = params_dict.get(_fmin)
50 |
51 | if f0 is not None and fmin is not None and fmin != 0:
52 | params_dict[_f0] = f0 / fmin
53 |
54 | wft, frequency = package.wft(signal_matlab, params.fs, params_dict, nargout=2)
55 |
56 | return wft, frequency
57 |
--------------------------------------------------------------------------------
/src/maths/algorithms/multiprocessing/bandpass_filter.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import Tuple
17 |
18 | import numpy as np
19 | from pymodalib.implementations.python.filtering import loop_butter
20 | from scipy.signal import hilbert
21 | from numpy import ndarray
22 | from maths.signals.TimeSeries import TimeSeries
23 |
24 | from processes.mp_utils import process
25 |
26 |
27 | @process
28 | def _bandpass_filter(
29 | time_series: TimeSeries, fmin, fmax, fs
30 | ) -> Tuple[str, ndarray, ndarray, ndarray, Tuple[float, float]]:
31 | """
32 | Performs the bandpass filter on a signal. Used in ridge-extraction and filtering.
33 |
34 | :param time_series: the signal
35 | :param fmin: the minimum frequency
36 | :param fmax: the maximum frequency
37 | :param fs: the sampling frequency
38 | :return:
39 | [str] name of the signal;
40 | [?] bands
41 | [1D array] phase
42 | [1D array] amplitude
43 | [tuple] the min and max frequencies
44 | """
45 | bands, _ = loop_butter(time_series.signal, fmin, fmax, fs)
46 | h = hilbert(bands)
47 |
48 | phase = np.angle(h)
49 | amp = np.abs(h)
50 |
51 | return time_series.name, bands, phase, amp, (fmin, fmax)
52 |
--------------------------------------------------------------------------------
/src/maths/algorithms/multiprocessing/bayesian_inference.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | from typing import Tuple
18 |
19 | import pymodalib
20 | from numpy import ndarray
21 |
22 | from gui.windows.bayesian.ParamSet import ParamSet
23 | from maths.signals.TimeSeries import TimeSeries
24 | from processes.mp_utils import process
25 |
26 |
27 | @process
28 | def _dynamic_bayesian_inference(
29 | signal1: TimeSeries, signal2: TimeSeries, params: ParamSet
30 | ) -> Tuple[
31 | str,
32 | ndarray,
33 | ndarray,
34 | ndarray,
35 | ndarray,
36 | ndarray,
37 | ndarray,
38 | ndarray,
39 | ndarray,
40 | ndarray,
41 | ndarray,
42 | ndarray,
43 | ]:
44 | sig1 = signal1.signal
45 | sig2 = signal2.signal
46 |
47 | interval1, interval2 = params.freq_range1, params.freq_range2
48 |
49 | fs = signal1.frequency
50 | bn = params.order
51 |
52 | win = params.window
53 | ovr = params.overlap
54 | pr = params.propagation_const
55 | signif = params.confidence_level
56 |
57 | result = pymodalib.bayesian_inference(
58 | sig1,
59 | sig2,
60 | fs=fs,
61 | interval1=interval1,
62 | interval2=interval2,
63 | surrogates=params.surr_count,
64 | window=win,
65 | overlap=ovr,
66 | order=bn,
67 | propagation_const=pr,
68 | signif=signif,
69 | )
70 |
71 | return (signal1.name, *result)
72 |
--------------------------------------------------------------------------------
/src/maths/algorithms/wpc.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | """
18 | Translation of the wavelet phase coherence algorithm from MODA.
19 |
20 | STATUS: Finished, although surrogates are not complete (see `surrogates.py`).
21 | """
22 | from typing import Tuple
23 |
24 | import numpy as np
25 | from numpy import ndarray
26 | from pymodalib.algorithms.coherence import tlphcoh, wphcoh
27 |
28 |
29 | def wpc(
30 | wt1: ndarray, wt2: ndarray, freq: ndarray, fs: float, wsize: int = 10
31 | ) -> Tuple[ndarray, ndarray, ndarray]:
32 | """
33 | Wavelet phase coherence.
34 |
35 | :param wt1: wavelet transform of the first signal
36 | :param wt2: wavelet transform of the second signal
37 | :param freq: frequencies at which transforms were calculated
38 | :param fs: sampling frequency
39 | :param wsize: window size
40 | :return: [2D array] absolute value of time-localised phase coherence; [1D array] phase coherence; [1D array] phase difference
41 | """
42 | tlpc = tlphcoh(wt1, wt2, freq, fs, wsize)
43 | pc, pdiff = wphcoh(wt1, wt2)
44 | return np.abs(tlpc), pc, pdiff
45 |
--------------------------------------------------------------------------------
/src/maths/params/BAParams.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from maths.signals.Signals import Signals
17 |
18 |
19 | class BAParams:
20 | def __init__(
21 | self,
22 | signals: Signals,
23 | fmin: float,
24 | fmax: float,
25 | f0: float,
26 | preprocess: bool,
27 | nv: float,
28 | surr_count: int,
29 | alpha: float,
30 | opt: dict,
31 | ):
32 | self.signals = signals
33 | self.fmin = fmin
34 | self.fmax = fmax
35 | self.f0 = f0
36 | self.preprocess = preprocess
37 | self.nv = nv
38 | self.surr_count = surr_count
39 | self.alpha = alpha
40 | self.fs = signals.frequency
41 |
42 | # The MATLAB algorithm returns a struct, `opt`, which is converted to this dict.
43 | self.opt = opt
44 |
--------------------------------------------------------------------------------
/src/maths/params/DBParams.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from maths.params.PCParams import PCParams
17 | from maths.params.TFParams import _wft
18 | from maths.signals.Signals import Signals
19 |
20 |
21 | class DBParams(PCParams):
22 |
23 | def __init__(self,
24 | signals: Signals,
25 | fmin=0,
26 | fmax=None,
27 | fstep="auto",
28 | f0=1,
29 | padding="predictive",
30 | cut_edges=False,
31 | window="Gaussian", # Just for WFT.
32 | wavelet="Lognorm", # Just for WT.
33 | preprocess=True,
34 | rel_tolerance=0.01,
35 | transform=_wft,
36 |
37 | # Added in BAParams.
38 | fc: float = None,
39 | nv: float = None,
40 |
41 | # Added in PCParams.
42 | surr_enabled=False,
43 | surr_count=0,
44 | surr_method="RP",
45 | surr_preproc=False):
46 | super().__init__(signals,
47 | fmin,
48 | fmax,
49 | fstep,
50 | f0,
51 | padding,
52 | cut_edges,
53 | window,
54 | wavelet,
55 | preprocess,
56 | rel_tolerance,
57 | transform,
58 |
59 | surr_enabled,
60 | surr_count,
61 | surr_method,
62 | surr_preproc)
63 |
64 | self.data["nv"] = nv
65 | self.data["fc"] = fc
66 |
--------------------------------------------------------------------------------
/src/maths/params/DHParams.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import List, Dict
17 |
18 | from maths.params.TFParams import TFParams
19 | from utils.dict_utils import sanitise
20 |
21 |
22 | class DHParams(TFParams):
23 | def __init__(
24 | self, signals, scale_min, scale_max, time_res, sigma, surr_count, crop
25 | ):
26 | super(DHParams, self).__init__(signals)
27 |
28 | self.crop = crop
29 | self.surr_count = surr_count
30 | self.sigma = sigma
31 | self.time_res = time_res
32 | self.scale_max = scale_max
33 | self.scale_min = scale_min
34 |
35 | def args(self) -> List:
36 | items = (
37 | self.fs,
38 | self.scale_min,
39 | self.scale_max,
40 | self.sigma,
41 | self.time_res,
42 | self.surr_count,
43 | )
44 | return [i for i in items if i is not None]
45 |
46 | def items_to_save(self) -> Dict:
47 | return sanitise(
48 | {
49 | "crop": self.crop,
50 | "surrogates": self.surr_count,
51 | "sigma": self.sigma,
52 | "scale_max": self.scale_max,
53 | "scale_min": self.scale_min,
54 | "time_res": self.time_res,
55 | }
56 | )
57 |
--------------------------------------------------------------------------------
/src/maths/params/PCParams.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import Dict
17 |
18 | from maths.params.TFParams import TFParams, _wft
19 | from maths.signals.Signals import Signals
20 | from utils.decorators import override
21 | from utils.dict_utils import sanitise
22 |
23 |
24 | class PCParams(TFParams):
25 | def __init__(
26 | self,
27 | signals: Signals,
28 | fmin=0,
29 | fmax=None,
30 | fstep="auto",
31 | f0=1,
32 | padding="predictive",
33 | cut_edges=False,
34 | window="Gaussian",
35 | wavelet="Lognorm",
36 | preprocess=True,
37 | rel_tolerance=0.01,
38 | transform=_wft,
39 | # Parameters not passed to Matlab.
40 | surr_enabled=False,
41 | surr_count=0,
42 | surr_method="RP",
43 | surr_preproc=False,
44 | ):
45 | if not surr_enabled:
46 | surr_count = 0
47 |
48 | self.surr_count = surr_count
49 | self.surr_method = surr_method
50 | self.surr_preproc = surr_preproc
51 |
52 | super().__init__(
53 | signals,
54 | fmin,
55 | fmax,
56 | fstep,
57 | f0,
58 | padding,
59 | cut_edges,
60 | window,
61 | wavelet,
62 | preprocess,
63 | rel_tolerance,
64 | transform,
65 | )
66 |
67 | @override
68 | def items_to_save(self) -> Dict:
69 | tf = super().items_to_save()
70 |
71 | out = {"surr_count": self.surr_count, "surr_type": self.surr_method, **tf}
72 | return sanitise(out)
73 |
--------------------------------------------------------------------------------
/src/maths/params/REParams.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | from maths.params.TFParams import TFParams, _wft, _fmin, _fmax
18 | from maths.signals.Signals import Signals
19 | from utils.decorators import deprecated
20 |
21 |
22 | class REParams(TFParams):
23 | def __init__(
24 | self,
25 | signals: Signals,
26 | fmin=None,
27 | fmax=None,
28 | fstep="auto",
29 | f0=1,
30 | padding="predictive",
31 | cut_edges=False,
32 | window="Gaussian",
33 | wavelet="Lognorm",
34 | preprocess=True,
35 | rel_tolerance=0.01,
36 | transform=_wft,
37 | # Added in REParams.
38 | method=2,
39 | param=None,
40 | normalize=False,
41 | path_opt=True,
42 | max_iterations=20,
43 | cache_file=None,
44 | intervals=None,
45 | ):
46 | super().__init__(
47 | signals,
48 | fmin,
49 | fmax,
50 | fstep,
51 | f0,
52 | padding,
53 | cut_edges,
54 | window,
55 | wavelet,
56 | preprocess,
57 | rel_tolerance,
58 | transform,
59 | )
60 |
61 | self.intervals = intervals
62 |
63 | # Add params not used in TFParams.
64 | self.data["Method"] = method
65 |
66 | if param:
67 | self.data["Param"] = param # Not tested, may not work.
68 |
69 | self.data["Normalize"] = normalize
70 | self.data["PathOpt"] = path_opt
71 | self.data["MaxIter"] = max_iterations
72 |
73 | if cache_file:
74 | self.data["CachedDataLocation"] = cache_file
75 |
76 | if fmin is None:
77 | self.delete(_fmin)
78 | else:
79 | self.data[_fmin] = fmin
80 |
81 | if fmax is None:
82 | self.delete(_fmax)
83 | else:
84 | self.data[_fmax] = fmax
85 |
86 | self.data["Display"] = "off"
87 |
88 | @deprecated
89 | def set_cache_file(self, file: str) -> None:
90 | self.data["CachedDataLocation"] = file
91 |
--------------------------------------------------------------------------------
/src/maths/signals/data/BAOutputData.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import Dict
17 |
18 | from dataclasses import dataclass
19 | from numpy import ndarray
20 |
21 |
22 | @dataclass
23 | class BAOutputData:
24 | """
25 | Data class containing data returned by bispectrum analysis.
26 | """
27 |
28 | # Amplitude and power of wavelet transform 1.
29 | amp_wt1: ndarray
30 | pow_wt1: ndarray
31 |
32 | # Average amplitude and power of wavelet transform 1.
33 | avg_amp_wt1: ndarray
34 | avg_pow_wt1: ndarray
35 |
36 | # Amplitude and power of wavelet transform 2.
37 | amp_wt2: ndarray
38 | pow_wt2: ndarray
39 |
40 | # Average amplitude and power of wavelet transform 2.
41 | avg_amp_wt2: ndarray
42 | avg_pow_wt2: ndarray
43 |
44 | times: ndarray
45 | freq: ndarray
46 |
47 | # Bispectra.
48 | bispxxx: ndarray
49 | bispppp: ndarray
50 | bispxpp: ndarray
51 | bisppxx: ndarray
52 |
53 | # Surrogates.
54 | surrxxx: ndarray
55 | surrppp: ndarray
56 | surrxpp: ndarray
57 | surrpxx: ndarray
58 |
59 | opt: dict
60 |
61 | biamp: Dict[float, ndarray]
62 | biphase: Dict[float, ndarray]
63 |
64 | def invalidate(self):
65 | amp_wt1: ndarray = None
66 | pow_wt1: ndarray = None
67 | avg_amp_wt1: ndarray = None
68 | avg_pow_wt1: ndarray = None
69 | amp_wt2: ndarray = None
70 | pow_wt2: ndarray = None
71 | avg_amp_wt2: ndarray = None
72 | avg_pow_wt2: ndarray = None
73 | times: ndarray = None
74 | freq: ndarray = None
75 | bispxxx: ndarray = None
76 | bispppp: ndarray = None
77 | bispxpp: ndarray = None
78 | bisppxx: ndarray = None
79 | surrxxx: ndarray = None
80 | surrppp: ndarray = None
81 | surrxpp: ndarray = None
82 | surrpxx: ndarray = None
83 | opt: dict = None
84 | biamp: Dict[float, ndarray] = None
85 | biphase: Dict[float, ndarray] = None
86 |
--------------------------------------------------------------------------------
/src/maths/signals/data/DBOutputData.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 |
18 | class DBOutputData:
19 |
20 | def __init__(self,
21 | tm,
22 | p1,
23 | p2,
24 | cpl1,
25 | cpl2,
26 | cf1,
27 | cf2,
28 | mcf1,
29 | mcf2,
30 | surr_cpl1,
31 | surr_cpl2):
32 | self.tm = tm
33 | self.surr_cpl2 = surr_cpl2
34 | self.surr_cpl1 = surr_cpl1
35 | self.mcf2 = mcf2
36 | self.mcf1 = mcf1
37 | self.cf2 = cf2
38 | self.cf1 = cf1
39 | self.cpl2 = cpl2
40 | self.cpl1 = cpl1
41 | self.p2 = p2
42 | self.p1 = p1
43 |
--------------------------------------------------------------------------------
/src/updater/CleanupThread.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | import logging
17 | import os
18 | import shutil
19 | import time
20 | from os.path import join
21 |
22 | from PyQt5.QtCore import QThread
23 |
24 | from utils import launcher, shortcuts
25 |
26 |
27 | class CleanupThread(QThread):
28 | """
29 | Thread which deletes old installations of PyMODA.
30 | """
31 |
32 | def run(self) -> None:
33 | time.sleep(5)
34 | launcher_dir = launcher.get_launcher_directory()
35 |
36 | import re
37 |
38 | pattern = "v[0-9].[0-9].[0-9]"
39 | versions = filter(lambda i: re.match(pattern, i), os.listdir(launcher_dir))
40 |
41 | versions = sorted(list(versions))
42 | logging.info(f"Currently installed versions: {versions}.")
43 |
44 | if len(versions) > 1:
45 | to_delete = versions[:-1]
46 |
47 | import main
48 |
49 | if main.__version__ in to_delete:
50 | logging.error(
51 | f"Cannot delete version {main.__version__}; it is the current version."
52 | )
53 | return
54 |
55 | for v in to_delete:
56 | logging.info(f"Deleting old version: {v}")
57 | path = join(launcher_dir, v)
58 | shutil.rmtree(path)
59 |
60 | # Fix issue where shortcut linked to an older version breaks because older version is deleted.
61 | shortcuts.create_shortcut()
62 |
--------------------------------------------------------------------------------
/src/updater/check.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import List, Tuple
17 |
18 | from github import Github
19 | from github.GitRelease import GitRelease
20 |
21 | g = Github()
22 |
23 |
24 | def _tuple_version(version_tag: str) -> Tuple[int, int, int]:
25 | return tuple([int(v) for v in version_tag.replace("v", "").split(".")])
26 |
27 |
28 | def is_version_newer(new: str, old: str) -> bool:
29 | return _tuple_version(new) > _tuple_version(old)
30 |
31 |
32 | def is_update_available() -> Tuple[bool, str]:
33 | import main
34 |
35 | releases = get_releases()
36 |
37 | latest = releases[0]
38 | return is_version_newer(latest.title, main.__version__), latest.title
39 |
40 |
41 | def get_releases() -> List[GitRelease]:
42 | repo = g.get_repo("luphysics/PyMODA")
43 |
44 | releases = repo.get_releases()
45 | return releases
46 |
--------------------------------------------------------------------------------
/src/utils/__init__.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | import sys
17 |
18 | is_frozen = frozen = getattr(sys, "frozen", False)
19 |
--------------------------------------------------------------------------------
/src/utils/cache.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | import os
17 | import shutil
18 |
19 | import scipy.io
20 |
21 |
22 | def clear():
23 | c = Cache()
24 | c.clear_all()
25 |
26 |
27 | class Cache:
28 |
29 | def __init__(self):
30 | self.cache = self.get_cache_location()
31 | try:
32 | os.mkdir(self.cache)
33 | except:
34 | pass
35 |
36 | @staticmethod
37 | def get_cache_location() -> str:
38 | base = os.getcwd()
39 |
40 | # If current directory is src, then create cache
41 | # in directory above.
42 | if base.split("/")[-1] == "src":
43 | base = f"{base}/.."
44 |
45 | return f"{base}/cache"
46 |
47 | def get_file_names(self) -> list:
48 | return os.listdir(self.cache)
49 |
50 | def generate_file_name(self, extension=".mat") -> str:
51 | # Get names of existing files without their file extensions.
52 | names = [".".join(name.split(".")[:-1]) for name in self.get_file_names()]
53 |
54 | i = -1
55 | while True:
56 | i += 1
57 | n = self._name_template(i)
58 |
59 | if n not in names:
60 | break
61 |
62 | return f"{n}{extension}"
63 |
64 | def get_path_to(self, file: str) -> str:
65 | return f"{self.cache}/{file}"
66 |
67 | def save_data(self, **kwargs) -> str:
68 | name = self.generate_file_name()
69 | path = self.get_path_to(name)
70 | scipy.io.savemat(path, kwargs)
71 | return path
72 |
73 | def clear_all(self):
74 | """
75 | Removes the cache folder and all its contents.
76 |
77 | The cache folder will be recreated next time
78 | Cache is instantiated.
79 | """
80 | shutil.rmtree(self.cache)
81 |
82 | @staticmethod
83 | def _name_template(index) -> str:
84 | return f"data{index}"
85 |
--------------------------------------------------------------------------------
/src/utils/dict_utils.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from typing import Dict
17 |
18 |
19 | def sanitise(dictionary: Dict) -> Dict:
20 | """
21 | Creates a sanitised copy of a dictionary, removing all None items.
22 | Does not modify the existing dictionary.
23 |
24 | :param dictionary: the dictionary to remove None items from
25 | :return: the new dictionary
26 | """
27 | new = {}
28 |
29 | for key, value in dictionary.items():
30 | if key is not None and value is not None:
31 | new[key] = value
32 |
33 | return new
34 |
--------------------------------------------------------------------------------
/src/utils/file_utils.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | import os
17 | import warnings
18 | from os import path
19 | from os.path import join
20 |
21 | from utils.os_utils import OS
22 |
23 | pymoda_path = None
24 |
25 | username = os.environ.get("USERNAME") or os.environ.get("USER")
26 | home = os.path.expanduser("~")
27 |
28 | if OS.is_windows():
29 | pymoda_path = f"C:\\Users\\{username}\\AppData\\Roaming\\PyMODA"
30 | else:
31 | pymoda_path = f"{home}/.pymoda"
32 |
33 | os.makedirs(pymoda_path, exist_ok=True)
34 |
35 | log_path = join(pymoda_path, "pymoda.log")
36 | settings_path = join(pymoda_path, "settings.conf")
37 |
38 | _whitelist = ["src", "res"]
39 |
40 |
41 | def get_root_folder() -> str:
42 | """
43 | Returns the absolute path to PyMODA's root folder.
44 |
45 | WARNING: This function relies on the fact that the current working directory points to `src/`.
46 | """
47 | _, folder = path.split(os.getcwd())
48 | # if folder not in _whitelist:
49 | if not any([f in _whitelist for f in os.listdir(os.getcwd())]):
50 | import inspect
51 |
52 | warnings.warn(
53 | f"\nWARNING: function '{inspect.currentframe().f_code.co_name}' is attempting to find "
54 | f"PyMODA's root directory, but the current working directory may not be the root directory."
55 | f"The current working directory is '{os.getcwd()}'.",
56 | RuntimeWarning,
57 | )
58 |
59 | return os.getcwd()
60 |
--------------------------------------------------------------------------------
/src/utils/launcher.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | import os
17 | import subprocess
18 | import sys
19 | from os.path import join
20 |
21 | from utils import file_utils
22 | from utils.os_utils import OS
23 |
24 |
25 | def get_launcher_directory() -> str:
26 | return file_utils.pymoda_path
27 |
28 |
29 | def is_launcher_present() -> bool:
30 | return any(
31 | [
32 | name in os.listdir(get_launcher_directory())
33 | for name in ["launcher", "launcher.exe"]
34 | ]
35 | )
36 |
37 |
38 | def get_launcher_path() -> str:
39 | folder = get_launcher_directory()
40 |
41 | target = join(folder, _get_launcher_name())
42 |
43 | if os.path.exists(target):
44 | return target
45 | else:
46 | return None
47 |
48 |
49 | def _get_launcher_name() -> str:
50 | return "launcher.exe" if OS.is_windows() else "launcher"
51 |
52 |
53 | def start_via_launcher() -> None:
54 | target = get_launcher_path()
55 | if not target:
56 | return
57 |
58 | subprocess.Popen([target, *sys.argv[1:]])
59 |
--------------------------------------------------------------------------------
/src/utils/log_utils.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | import datetime
17 | import logging
18 | import os
19 | from logging.handlers import RotatingFileHandler
20 | from os.path import join
21 |
22 | from utils import file_utils, errorhandling
23 |
24 | global_filename = None # Only used by processes on macOS/Linux.
25 |
26 |
27 | def init(filepath: str = None) -> None:
28 | if filepath:
29 | log_path = filepath
30 | else:
31 | log_path = file_utils.log_path
32 |
33 | logging.basicConfig(filename=log_path, level=logging.INFO)
34 | log = logging.getLogger("root")
35 |
36 | handler = RotatingFileHandler(log_path, mode="a", maxBytes=1024 * 1024 * 10)
37 | log.addHandler(handler)
38 |
39 |
40 | def process_init() -> None:
41 | """
42 | Initialise logging for a process. Different processes need to log to different files,
43 | so each process can call this function to start logging.
44 | """
45 | filename = str(datetime.datetime.now()).replace(" ", "_").replace(":", "-")
46 | filename = ".".join(filename.split(".")[:-1])
47 |
48 | filepath = join(file_utils.pymoda_path, "processes")
49 | os.makedirs(filepath, exist_ok=True)
50 |
51 | global global_filename
52 | global_filename = join(filepath, f"{filename}.log")
53 |
54 | logging.basicConfig(filename=global_filename, level=logging.INFO)
55 | errorhandling.init()
56 |
57 |
58 | def process_write_log(msg: str) -> None:
59 | """
60 | Used by processes on macOS/Linux; writes a message to the log file manually.
61 |
62 | Parameters
63 | ----------
64 | msg : str
65 | The text to append to the log file.
66 | """
67 | global global_filename
68 |
69 | with open(global_filename, "a+") as f:
70 | f.write(msg)
71 |
--------------------------------------------------------------------------------
/src/utils/os_utils.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | import os
17 | import platform
18 |
19 | system = platform.system()
20 |
21 | # Variables used to test functionality from different operating systems.
22 | override_windows = "MOCKOS_WINDOWS" in os.environ
23 | override_linux = "MOCKOS_LINUX" in os.environ
24 | override_macos = "MOCKOS_MACOS" in os.environ
25 |
26 |
27 | class OS:
28 | @staticmethod
29 | def is_windows() -> bool:
30 | """
31 | Returns whether the current OS is Windows.
32 | """
33 | return override_windows or (
34 | system == "Windows" and not override_macos and not override_linux
35 | )
36 |
37 | @staticmethod
38 | def is_linux() -> bool:
39 | """
40 | Returns whether the current OS is Linux-based.
41 | """
42 | return override_linux or (
43 | system == "Linux" and not override_macos and not override_windows
44 | )
45 |
46 | @staticmethod
47 | def is_mac_os() -> bool:
48 | """
49 | Returns whether the current OS is macOS (hopefully).
50 | """
51 | return override_macos or (
52 | system == "Darwin" and not override_linux and not override_windows
53 | )
54 |
--------------------------------------------------------------------------------
/src/utils/qutils.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2020 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from PyQt5.QtWidgets import QWidget, QSizePolicy
17 |
18 |
19 | def retain_size_when_hidden(widget: QWidget) -> None:
20 | sizepolicy: QSizePolicy = widget.sizePolicy()
21 | sizepolicy.setRetainSizeWhenHidden(True)
22 | widget.setSizePolicy(sizepolicy)
23 |
--------------------------------------------------------------------------------
/src/utils/stdout_redirect.py:
--------------------------------------------------------------------------------
1 | # PyMODA, a Python implementation of MODA (Multiscale Oscillatory Dynamics Analysis).
2 | # Copyright (C) 2019 Lancaster University
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | import datetime
17 | import logging
18 | import sys
19 | import threading
20 |
21 |
22 | class StdOut:
23 | def write(self, text):
24 | # Output text as normal.
25 | sys_out.write(text)
26 |
27 | # Write to log file.
28 | logging.info(msg=text)
29 |
30 | # Notify subscribers.
31 | for s in subscribers:
32 | if threading.current_thread() is threading.main_thread():
33 | if isinstance(s, WindowLogger):
34 | s.update(text)
35 | else:
36 | s(text)
37 |
38 | def flush(self):
39 | return
40 |
41 |
42 | subscribers = [] # List of subscribers to be notified when stdout is used.
43 |
44 | out = StdOut() # The redirected stdout.
45 | sys_out = sys.__stdout__ # The original system stdout.
46 |
47 |
48 | def init():
49 | sys.stdout = out
50 |
51 |
52 | def subscribe(subscriber):
53 | subscribers.append(subscriber)
54 |
55 |
56 | def unsubscribe(subscriber):
57 | subscribers.remove(subscriber)
58 |
59 |
60 | class WindowLogger:
61 | """
62 | A class which handles logging to a log pane safely,
63 | without excessive memory usage. When the number of
64 | logged lines exceeds the max size, the first half
65 | of the lines are deleted.
66 | """
67 |
68 | def __init__(self, func, max_lines=200):
69 | self.func = func
70 | self.lines = []
71 | self.max_lines = max_lines
72 |
73 | def update(self, text):
74 | if text == "\n":
75 | return
76 |
77 | self.lines.append(f"{self.get_time()} - {text}")
78 | count = len(self.lines)
79 |
80 | if count > self.max_lines:
81 | # Remove the first half of the lines to save memory.
82 | self.lines = self.lines[count // 2 :]
83 |
84 | self.func("\n".join(self.lines))
85 |
86 | @staticmethod
87 | def get_time() -> str:
88 | time = datetime.datetime.now()
89 | return f"{time:%H:%M:%S}"
90 |
--------------------------------------------------------------------------------