Skip to content

Commit

Permalink
Merge pull request #170 from RichieHakim/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
RichieHakim authored Jan 28, 2024
2 parents a3caf92 + 41f534c commit 5196f4a
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 99 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
windows-2022,
windows-2019,
# # macos-latest,
# macos-12.0,
macos-12,
macos-11.0,
# macos-10.15,
]
Expand Down
10 changes: 5 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ kymatio==0.3.0
matplotlib==3.8.2
natsort==8.4.0
numpy==1.26.3
opencv_contrib_python==4.8.1.78
optuna==3.4.0
opencv_contrib_python<=4.9.0.80
optuna==3.5.0
Pillow==10.2.0
pytest==7.4.4
scikit_learn==1.4.0
scipy==1.12.0
seaborn==0.13.1
seaborn==0.13.2
sparse==0.15.1
tqdm==4.66.1
umap_learn==0.5.5
xxhash==3.4.1
bokeh==3.3.3
bokeh==3.3.4
psutil==5.9.8
py_cpuinfo==9.0.0
GPUtil==1.4.0
Expand All @@ -25,7 +25,7 @@ mat73==0.62
torch==2.1.2
torchvision==0.16.2
torchaudio==2.1.2
selenium==4.16.0
selenium==4.17.2
skl2onnx==1.16.0
onnx==1.15.0
onnxruntime==1.16.3
Expand Down
2 changes: 1 addition & 1 deletion roicat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
for pkg in __all__:
exec('from . import ' + pkg)

__version__ = '1.1.28'
__version__ = '1.1.29'
82 changes: 82 additions & 0 deletions roicat/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,88 @@ def flatten_dict(d: MutableMapping, parent_key: str = '', sep: str ='.') -> Muta
items.append((new_key, v))
return dict(items)

## parameter dictionary helpers ##

def fill_in_dict(
d: Dict,
defaults: Dict,
verbose: bool = True,
hierarchy: List[str] = ['dict'],
):
"""
In-place. Fills in dictionary ``d`` with values from ``defaults`` if they
are missing. Works hierachically.
RH 2023
Args:
d (Dict):
Dictionary to fill in.
In-place.
defaults (Dict):
Dictionary of defaults.
verbose (bool):
Whether to print messages.
hierarchy (List[str]):
Used internally for recursion.
Hierarchy of keys to d.
"""
from copy import deepcopy
for key in defaults:
if key not in d:
print(f"Key '{key}' not found in params dictionary: {' > '.join([f'{str(h)}' for h in hierarchy])}. Using default value: {defaults[key]}") if verbose else None
d.update({key: deepcopy(defaults[key])})
elif isinstance(defaults[key], dict):
assert isinstance(d[key], dict), f"Key '{key}' is a dict in defaults, but not in params. {' > '.join([f'{str(h)}' for h in hierarchy])}."
fill_in_dict(d[key], defaults[key], hierarchy=hierarchy+[key])


def check_keys_subset(d, default_dict, hierarchy=['defaults']):
"""
Checks that the keys in d are all in default_dict. Raises an error if not.
RH 2023
Args:
d (Dict):
Dictionary to check.
default_dict (Dict):
Dictionary containing the keys to check against.
hierarchy (List[str]):
Used internally for recursion.
Hierarchy of keys to d.
"""
default_keys = list(default_dict.keys())
for key in d.keys():
assert key in default_keys, f"Parameter '{key}' not found in defaults dictionary: {' > '.join([f'{str(h)}' for h in hierarchy])}."
if isinstance(default_dict[key], dict) and isinstance(d[key], dict):
check_keys_subset(d[key], default_dict[key], hierarchy=hierarchy+[key])


def prepare_params(params, defaults, verbose=True):
"""
Does the following:
* Checks that all keys in ``params`` are in ``defaults``.
* Fills in any missing keys in ``params`` with values from ``defaults``.
* Returns a deepcopy of the filled-in ``params``.
Args:
params (Dict):
Dictionary of parameters.
defaults (Dict):
Dictionary of defaults.
verbose (bool):
Whether to print messages.
"""
from copy import deepcopy
## Check inputs
assert isinstance(params, dict), f"p must be a dict. Got {type(params)} instead."
## Make sure all the keys in p are valid
check_keys_subset(params, defaults)
## Fill in any missing keys with defaults
params_out = deepcopy(params)
fill_in_dict(params_out, defaults, verbose=verbose)

return params_out


######################################################################################################################################
####################################################### MATH FUNCTIONS ###############################################################
Expand Down
4 changes: 2 additions & 2 deletions roicat/pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ def pipeline_tracking(params: dict):
pipeline.
params (dict):
Parameters used in the pipeline. See
``roicat.util.prepare_params()`` for details.
``roicat.helpers.prepare_params()`` for details.
"""

## Prepare params
defaults = util.get_default_parameters(pipeline='tracking')
params = util.prepare_params(params, defaults, verbose=True)
params = helpers.prepare_params(params, defaults, verbose=True)
display(params)

## Prepare state variables
Expand Down
78 changes: 0 additions & 78 deletions roicat/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,84 +250,6 @@ def get_default_parameters(

return out

def fill_in_params(
d: Dict,
defaults: Dict,
verbose: bool = True,
hierarchy: List[str] = ['params'],
):
"""
In-place. Fills in dictionary ``d`` with values from ``defaults`` if they
are missing. Works hierachically.
RH 2023
Args:
d (Dict):
Dictionary to fill in.
In-place.
defaults (Dict):
Dictionary of defaults.
verbose (bool):
Whether to print messages.
hierarchy (List[str]):
Used internally for recursion.
Hierarchy of keys to d.
"""
from copy import deepcopy
for key in defaults:
if key not in d:
print(f"Parameter '{key}' not found in params dictionary: {' > '.join([f'{str(h)}' for h in hierarchy])}. Using default value: {defaults[key]}") if verbose else None
d.update({key: deepcopy(defaults[key])})
elif isinstance(defaults[key], dict):
assert isinstance(d[key], dict), f"Parameter '{key}' must be a dictionary."
fill_in_params(d[key], defaults[key], hierarchy=hierarchy+[key])

def check_keys_subset(d, default_dict, hierarchy=['defaults']):
"""
Checks that the keys in d are all in default_dict. Raises an error if not.
RH 2023
Args:
d (Dict):
Dictionary to check.
default_dict (Dict):
Dictionary containing the keys to check against.
hierarchy (List[str]):
Used internally for recursion.
Hierarchy of keys to d.
"""
default_keys = list(default_dict.keys())
for key in d.keys():
assert key in default_keys, f"Parameter '{key}' not found in defaults dictionary: {' > '.join([f'{str(h)}' for h in hierarchy])}."
if isinstance(default_dict[key], dict) and isinstance(d[key], dict):
check_keys_subset(d[key], default_dict[key], hierarchy=hierarchy+[key])

def prepare_params(params, defaults, verbose=True):
"""
Does the following:
* Checks that all keys in ``params`` are in ``defaults``.
* Fills in any missing keys in ``params`` with values from ``defaults``.
* Returns a deepcopy of the filled-in ``params``.
Args:
params (Dict):
Dictionary of parameters.
defaults (Dict):
Dictionary of defaults.
verbose (bool):
Whether to print messages.
"""
from copy import deepcopy
## Check inputs
assert isinstance(params, dict), f"p must be a dict. Got {type(params)} instead."
## Make sure all the keys in p are valid
check_keys_subset(params, defaults)
## Fill in any missing keys with defaults
params_out = deepcopy(params)
fill_in_params(params_out, defaults, verbose=verbose)

return params_out


def system_info(verbose: bool = False,) -> Dict:
"""
Expand Down
43 changes: 32 additions & 11 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
## setup.py file for roicat
from pathlib import Path
import copy
import platform

from distutils.core import setup
import copy

## Get the parent directory of this file
dir_parent = Path(__file__).parent

## Get requirements from requirements.txt
def read_requirements():
with open(str(dir_parent / "requirements.txt"), "r") as req:
content = req.read() ## read the file
Expand All @@ -19,15 +22,33 @@ def read_requirements():
requirements = [req.replace(",", "").replace("\"", "").replace("\'", "").strip() for req in requirements]

return requirements

deps_all = read_requirements()


## Dependencies: latest versions of requirements
### remove everything starting and after the first =,>,<,! sign
deps_names = [req.split('=')[0].split('>')[0].split('<')[0].split('!')[0] for req in deps_all]
deps_all_dict = dict(zip(deps_names, deps_all))

deps_all_latest = copy.deepcopy(deps_names)
deps_all_latest = dict(zip(deps_names, deps_names))


# Operating system specific dependencies
# OpenCV >= 4.9 is not supported on macOS < 12
system, version_macos = platform.system(), platform.mac_ver()[0]
print(f"System: {system}, macOS version: {version_macos}")
if (system == "Darwin"):
# Safely convert version string components to integers
version_parts = version_macos.split('.')
version_major_macos = int(version_parts[0])

# Check macOS version and adjust the OpenCV version accordingly
if (version_major_macos < 12) and ('opencv_contrib_python' in deps_all_dict):
version_opencv_macos_sub12 = "opencv_contrib_python<=4.8.1.78"
print(f"Detected macOS version {version_major_macos}, which is < 12. Installing an older version of OpenCV: {version_opencv_macos_sub12}")
deps_all_dict['opencv_contrib_python'] = version_opencv_macos_sub12
deps_all_latest['opencv_contrib_python'] = version_opencv_macos_sub12


## Make different versions of dependencies
### Also pull out the version number from the requirements (specified in deps_all_dict values).
Expand All @@ -53,30 +74,30 @@ def read_requirements():
'psutil',
'py_cpuinfo',
'GPUtil',
'skl2onnx',
'onnx',
'onnxruntime',
'opencv_contrib_python',
]]

deps_classification = [deps_all_dict[dep] for dep in [
'opencv_contrib_python',
'umap_learn',
'bokeh',
'holoviews[recommended]',
'jupyter_bokeh',
'skl2onnx',
'onnx',
'onnxruntime',
]] + deps_core

deps_tracking = [deps_all_dict[dep] for dep in [
'opencv_contrib_python',
'hdbscan',
'kymatio',
]] + deps_core


## Get README.md
with open(str(dir_parent / "README.md"), "r") as f:
readme = f.read()

## Get version number
## Get ROICaT version number
with open(str(dir_parent / "roicat" / "__init__.py"), "r") as f:
for line in f:
if line.startswith("__version__"):
Expand All @@ -103,8 +124,8 @@ def read_requirements():

install_requires=[],
extras_require={
'all': deps_all,
'all_latest': deps_all_latest,
'all': list(deps_all_dict.values()),
'all_latest': list(deps_all_latest.values()),
'core': deps_core,
'classification': deps_classification,
'tracking': deps_tracking,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def test_pipeline_tracking_simple(dir_data_test):
},
},
}
params = util.prepare_params(params_partial, defaults)
params = helpers.prepare_params(params_partial, defaults)
results, run_data, params = pipelines.pipeline_tracking(params)

#check that results fields are not empty
Expand Down

0 comments on commit 5196f4a

Please sign in to comment.