Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Python integration to PsPM UI #675

Merged
merged 23 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions src/pspm_cfg/pspm_cfg_pp_heart_data.m
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@

function pp_heart_data = pspm_cfg_pp_heart_data

% $Id: pspm_cfg_pp_heart_data.m 784 2019-07-08 08:16:46Z esrefo $
% $Rev: 784 $
% Updated 27-Mar-2024 by Teddy

% Initialise
global settings
Expand Down Expand Up @@ -192,12 +191,29 @@
'Heart beat conversion, or directly work on heart beat time stamps, ', ...
'for example obtained by a pulse oxymeter.']};

%% ppg2hb
ppg2hb_heartpy = pspm_cfg_python(1,'HeartPy');

ppg2hb_classic = cfg_const;
ppg2hb_classic.name = 'Classic';
ppg2hb_classic.tag = 'classic';
ppg2hb_classic.val = {0};
ppg2hb_classic.help = {'Analyse the data with the classic mode.'};

ppg2hb_method = cfg_choice;
ppg2hb_method.name = 'Select the method of converting the data';
ppg2hb_method.tag = 'method';
ppg2hb_method.val = {ppg2hb_classic};
ppg2hb_method.values = {ppg2hb_classic, ppg2hb_heartpy};
ppg2hb_method.help = {['Convert the PPG data into heart rate by using the ', ...
'selected method.']};

ppg2hb_chan = pspm_cfg_channel_selector('peripheral pulse oxymetry');

ppg2hb = cfg_exbranch;
ppg2hb.name = 'Convert Peripheral pulse oximetry to Heart Beat';
ppg2hb.name = 'Convert peripheral pulse oximetry to Heart Beat';
ppg2hb.tag = 'ppg2hb';
ppg2hb.val = {ppg2hb_chan};
ppg2hb.val = {ppg2hb_chan, ppg2hb_method};
ppg2hb.help = {['Convert Peripheral pulse oximetry to ', ...
'Heart Beat events.']};

Expand Down
67 changes: 67 additions & 0 deletions src/pspm_cfg/pspm_cfg_python.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
function out = pspm_cfg_python(varargin)
% ● Description
% pspm_cfg_python is a GUI function that provides UI controls for
% python definition
% ● Format
% out = pspm_cfg_python
% out = pspm_cfg_python(default_auto)
% out = pspm_cfg_python(python_package)
% out = pspm_cfg_python(default_auto, python_package)
% ● Arguments
% default_auto: [logical] The logical value that determines whether the
% to automatically detect python. If not determined, it
% will be set as 1.
% python_package: [string] the python package PsPM wants to use.
% out: [struct] The UI struct variable for python detection.
% ● History
% Written on 08-04-2024 by Teddy

%% Input checking
switch length(varargin)
case 0
default_auto = 1;
python_package = 'Python';
case 1
switch class(varargin{1})
case 'double'
default_auto = varargin{1};
python_package= 'Python';
case 'char'
default_auto = 1;
python_package= varargin{1};
end
case 2
default_auto = varargin{1};
python_package = varargin{2};
otherwise
warning('ID:invalid_input', 'Up to one input variable is allowed');
end
%% Structs
% automatically detect python
ppg2hb_py_auto = cfg_const;
ppg2hb_py_auto.name = 'Automatically detect Python';
ppg2hb_py_auto.tag = 'pypath_auto';
ppg2hb_py_auto.val = {0};
ppg2hb_py_auto.help = {['This only works if a Python environment ',...
'already exists in Matlab, created by ',...
'previous PsPM function calls or manually.']};
% manually detect python
pspm_py_path = cfg_files;
pspm_py_path.name = 'Manually define Python';
pspm_py_path.tag = 'pypath';
pspm_py_path.num = [1 1];
pspm_py_path.help = {'Please specify python executable file on the computer.'};
% the struct of python detection
pspm_py_detect = cfg_choice;
if default_auto
pspm_py_detect.val = {ppg2hb_py_auto};
else
pspm_py_detect.val = {pspm_py_path};
end
pspm_py_detect.values = {ppg2hb_py_auto, pspm_py_path};
pspm_py_detect.name = python_package;
pspm_py_detect.tag = python_package;
pspm_py_detect.help = {['Use ',python_package,' to analyse the input data. ',...
'Please select how to detect Python in the following.']};
%% Output
out = pspm_py_detect;
12 changes: 10 additions & 2 deletions src/pspm_cfg/pspm_cfg_run_pp_heart_data.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
function out = pspm_cfg_run_pp_heart_data(job)
% Updated on 08-01-2024 by Teddy
% Updated on 26-03-2024 by Teddy
fn = job.datafile{1};
outputs = cell(size(job.pp_type));
for i = 1:numel(job.pp_type)
Expand Down Expand Up @@ -64,6 +64,14 @@
end
case 'ppg2hb'
options = struct();
if ~isfield(job.pp_type{i}.ppg2hb.method, 'HeartPy')
options.method = 'classic';
else
options.method = 'heartpy';
if isfield(job.pp_type{i}.ppg2hb.method.HeartPy, 'pypath')
options.python_path = job.pp_type{i}.ppg2hb.method.HeartPy.pypath{1};
end
end
options.channel = chan;
options = pspm_update_struct(options, job, {'channel_action'});
[sts, winfo] = pspm_convert_ppg2hb(fn, options);
Expand All @@ -76,4 +84,4 @@
end
end
end
out = {fn};
out = {fn};
53 changes: 0 additions & 53 deletions src/pspm_check_python

This file was deleted.

18 changes: 11 additions & 7 deletions src/pspm_check_python.m
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
function sts = pspm_check_python(pythonPath)
% pspm_check_python Checks and sets the Python environment if path is provided.
% ● Description
% pspm_check_python Checks and sets the Python environment if path is provided.
%
% This function checks the current Python environment setup in MATLAB.
% If a specific Python executable path is provided, the function attempts
% to update the Python environment to use the provided path.
% It returns a status argument sts with values 0 or 1.
% This function checks the current Python environment setup in MATLAB.
% If a specific Python executable path is provided, the function attempts
% to update the Python environment to use the provided path.
% It returns a status argument sts with values 0 or 1.
%
% Arguments:
% Arguments
% pythonPath - A string specifying the path to the Python executable.
% If this is empty or not provided, the function simply
% reports the current Python environment without making changes.
%
% Returns:
% Returns
% sts - Status of the operation (1 for success, 0 for failure).
%
% ● History
% Written in 2024 by Dominik R Bach (Uni Bonn)

% Initialize the status to failure
sts = 0;
Expand Down
35 changes: 26 additions & 9 deletions src/pspm_check_python_modules.m
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
function moduleNames = pspm_check_python_modules()
% pspm_check_python_modules Returns a list of currently imported Python modules in MATLAB.
function [sts, moduleNames] = pspm_check_python_modules(module)
% ● Description
% pspm_check_python_modules Returns a list of currently imported Python modules in MATLAB.
%
% This function retrieves and returns the names of Python modules that have been imported
% into the current MATLAB session.
% This function retrieves and returns the names of Python modules that have been imported
% into the current MATLAB session. If a module name is provided as
% argument, will try to load this module of not already loaded
%
% ● History
% Written in 2024 by Dominik R Bach (Uni Bonn)

% Initialize return variable
% Initialize return variables
sts = 0;
moduleNames = {};

try
% Ensure Python is correctly set up in MATLAB
pe = pyenv();
if strcmp(pe.Version, "")
fprintf('Python environment does not exist. Run ''pspm_check_python()'' to ensure that the environment is correctly set up.\n');
if strcmp(pe.Version, '')
warning('Python environment does not exist. Run ''pspm_check_python()'' to ensure that the environment is correctly set up.\n');
return;
elseif ~strcmp(pe.Status, "Loaded")
elseif ~strcmp(pe.Status, 'Loaded')
fprintf('No module is loaded yet.\n');
return;
else
% Get the dictionary of imported Python modules
modulesDict = py.sys.modules;
moduleNamesList = py.list(modulesDict.keys());
moduleNames = cell(moduleNamesList);
moduleNames = cellfun(@(x) char(x), moduleNames, 'UniformOutput', false);

% Print confirmation message
fprintf('Python modules have been successfully retrieved. Total modules: %d\n', numel(moduleNames));
end
catch ME
fprintf('An error occurred while retrieving Python modules: %s\n', ME.message);
return
end

if nargin > 0 && ischar(module) && ~ismember(module, moduleNames)
try
py.importlib.import_module(module);
catch ME
warning('An error occurred while loading Python modules: %s\n', ME.message);
return
end
end
sts = 1;
end
Loading
Loading