From afdd8bff021e0ecd88505b0c4816fb4801732d97 Mon Sep 17 00:00:00 2001 From: sina Date: Fri, 27 May 2022 12:04:12 +1000 Subject: [PATCH 1/8] updated git ignore to ignore pypi tokens --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 64c2ac1..822ae2c 100755 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ connectome-spatial-smoothing.sublime-workspace # test notebooks code/Connectome_Spatial_Smoothing/__pycache__/ notebooks/temp.ipynb + +# ignore the pypi toke +token.tmp From b13ecc44488f8a1e3a68cf9fb66151b8c87b94f1 Mon Sep 17 00:00:00 2001 From: sina-mansour Date: Mon, 7 Aug 2023 16:15:46 +0800 Subject: [PATCH 2/8] added the functionality to disable css logs --- README.md | 10 ++++++++++ code/Connectome_Spatial_Smoothing/CSS.py | 14 ++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bbc94d7..f61118a 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,16 @@ Then, you could simply use the package in your own code after importing: --- +## Usage notes + +### Verbosity: + +By default CSS scripts print out a bunch of logs that may or may not be of interest to you. If you like to disable the logs, simply add the following script: + +`css._verbose = False` + +--- + We have provided a short jupyter notebook showcasing all the functionalities described above. You may use the following link to open [this notebook](https://github.com/sina-mansour/connectome-based-smoothing/blob/main/notebooks/example.ipynb) in an interactive google colab session: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/sina-mansour/connectome-based-smoothing/blob/main/notebooks/example.ipynb) diff --git a/code/Connectome_Spatial_Smoothing/CSS.py b/code/Connectome_Spatial_Smoothing/CSS.py index cb0d968..fbc1f2e 100644 --- a/code/Connectome_Spatial_Smoothing/CSS.py +++ b/code/Connectome_Spatial_Smoothing/CSS.py @@ -29,6 +29,7 @@ _main_dir = os.path.abspath(os.path.dirname(__file__)) _sample_cifti_dscalar = os.path.join(_main_dir, 'data/templates/cifti/ones.dscalar.nii') _glasser_cifti = os.path.join(_main_dir, 'data/templates/atlas/Glasser360.32k_fs_LR.dlabel.nii') +_verbose=True def _join_path(*args): @@ -44,12 +45,13 @@ def _load_sparse(file_path): def _time_str(mode='abs', base=None): - if mode == 'rel': - return str(datetime.timedelta(seconds=(time.time() - base))) - if mode == 'raw': - return time.time() - if mode == 'abs': - return time.asctime(time.localtime(time.time())) + if _verbose: + if mode == 'rel': + return str(datetime.timedelta(seconds=(time.time() - base))) + if mode == 'raw': + return time.time() + if mode == 'abs': + return time.asctime(time.localtime(time.time())) def _print_log(message, mode='info'): From 93ef082dae58b02d84d7870e016548649513ee9f Mon Sep 17 00:00:00 2001 From: sina-mansour Date: Mon, 7 Aug 2023 16:36:04 +0800 Subject: [PATCH 3/8] added support for sift2 weights, according to suggested changes by @jaysonjeg from #9 --- code/Connectome_Spatial_Smoothing/CSS.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/code/Connectome_Spatial_Smoothing/CSS.py b/code/Connectome_Spatial_Smoothing/CSS.py index fbc1f2e..12c3d91 100644 --- a/code/Connectome_Spatial_Smoothing/CSS.py +++ b/code/Connectome_Spatial_Smoothing/CSS.py @@ -603,11 +603,19 @@ def _get_half_incidence_matrices_from_endpoint_distances(start_dists, end_dists, end_indices, node_count, - threshold): + threshold, + weights=None): """ Returns two half incidence matrices in a sparse format (CSR) after filtering the streamlines that are far (>2mm) from their closest vertex. """ + + if weights is None: + weights = np.ones(len(start_dists)) + elif (type(weights) == str): + # load text file contents (this could be sift weights files generated by mrtrix) + weights = np.genfromtxt(weights) + # mask points that are further than the threshold from all surface coordinates outlier_mask = (start_dists > threshold) | (end_dists > threshold) _print_log('outliers located: #{} outliers ({}%, with threshold {}mm)'.format( @@ -622,7 +630,7 @@ def _get_half_incidence_matrices_from_endpoint_distances(start_dists, end_dict = {} indices = (i for i in range(len(outlier_mask)) if not outlier_mask[i]) for l, i in enumerate(indices): - start_dict[(start_indices[i], l)] = start_dict.get((start_indices[i], l), 0) + 1 + start_dict[(start_indices[i], l)] = start_dict.get((start_indices[i], l), 0) + weights[i] end_dict[(end_indices[i], l)] = end_dict.get((end_indices[i], l), 0) + 1 start_inc_mat = sparse.dok_matrix( @@ -666,7 +674,8 @@ def map_high_resolution_structural_connectivity(track_file, warp_file=None, threshold=2, subcortex=False, - cifti_file=_sample_cifti_dscalar,): + cifti_file=_sample_cifti_dscalar, + weights=None): """ Map the high-resolution structural connectivity matrix from tractography outputs. @@ -691,6 +700,11 @@ def map_high_resolution_structural_connectivity(track_file, to determine the high-resolution structure to exclude the medial wall and potentially integrate subcortical volume. + weights: [optional] A numpy vector with the length of number of streamlines, or a file path + pointing to a per-streamline weights file (such as the files generated by mrtrix's + tcksift2). If this file is provided, then the weights are used to adjust the + contribution of every streamline to the connectivity matrix. + Returns: connectome: The high-resolution structural connectome in a sparse csr format. @@ -705,7 +719,8 @@ def map_high_resolution_structural_connectivity(track_file, warp_file, subcortex=subcortex, ), - threshold=threshold + threshold=threshold, + weights=weights ) ) From 92fd0fb09628147d4fc898b1e16f9f4180c418bf Mon Sep 17 00:00:00 2001 From: sina-mansour Date: Mon, 7 Aug 2023 17:48:01 +0800 Subject: [PATCH 4/8] added support for computing a mean statistic along each edge (e.g. can be used to derive mean length/FA, see #8) --- code/Connectome_Spatial_Smoothing/CSS.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/code/Connectome_Spatial_Smoothing/CSS.py b/code/Connectome_Spatial_Smoothing/CSS.py index 12c3d91..f37e356 100644 --- a/code/Connectome_Spatial_Smoothing/CSS.py +++ b/code/Connectome_Spatial_Smoothing/CSS.py @@ -660,11 +660,15 @@ def _get_half_incidence_matrices_from_endpoint_distances(start_dists, return (start_inc_mat.tocsr(), end_inc_mat.tocsr()) -def _get_adjacency_from_half_incidence_matrices(U, V): +def _get_adjacency_from_half_incidence_matrices(U, V, stat='sum'): """ return a sparse adjacency matrix A from the two halfs of incidence matrix U & V. """ A = U.dot(V.T) + if stat == 'mean': + # compute average instead of sum + A_div = (U != 0).astype(int).dot(((V != 0).astype(int)).T) + A.data = A.data / A_div.data return A + A.T @@ -675,7 +679,8 @@ def map_high_resolution_structural_connectivity(track_file, threshold=2, subcortex=False, cifti_file=_sample_cifti_dscalar, - weights=None): + weights=None, + stat='sum'): """ Map the high-resolution structural connectivity matrix from tractography outputs. @@ -704,6 +709,10 @@ def map_high_resolution_structural_connectivity(track_file, pointing to a per-streamline weights file (such as the files generated by mrtrix's tcksift2). If this file is provided, then the weights are used to adjust the contribution of every streamline to the connectivity matrix. + stat: [optional, default='sum'] Either 'sum', or 'mean'. If sum, the values will be added up + over all streamlines. Otherwise an average is computed over all streamline weights. + combination of stat='mean' with a list of per-streamline lengths could be used to compute + a mean distance connectivity matrix. Returns: @@ -721,7 +730,8 @@ def map_high_resolution_structural_connectivity(track_file, ), threshold=threshold, weights=weights - ) + ), + stat=stat ) From 68bdb4c22c48f0c01d73d8c54e4092002fcd211c Mon Sep 17 00:00:00 2001 From: sina-mansour Date: Mon, 7 Aug 2023 17:58:21 +0800 Subject: [PATCH 5/8] attempting to resolve issue #10 --- code/Connectome_Spatial_Smoothing/CSS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/Connectome_Spatial_Smoothing/CSS.py b/code/Connectome_Spatial_Smoothing/CSS.py index f37e356..e899c87 100644 --- a/code/Connectome_Spatial_Smoothing/CSS.py +++ b/code/Connectome_Spatial_Smoothing/CSS.py @@ -208,7 +208,7 @@ def parcellation_characteristic_matrix(atlas_file=_glasser_cifti, cifti_file=_sa label_dict = {x: i for (i, x) in enumerate(labels)} - parcellation_matrix = np.zeros((len(labels), cortical_vertices_count)) + parcellation_matrix = np.zeros((len(labels), len(surface_labels))) for (i, x) in enumerate(surface_labels): parcellation_matrix[label_dict[x], i] = 1 From 7ab0f131c60669cbddfe236691b4975f94ae96bd Mon Sep 17 00:00:00 2001 From: sina-mansour Date: Mon, 7 Aug 2023 18:18:18 +0800 Subject: [PATCH 6/8] adding automation script to push the repository to PYPI upon creation of a new release --- .github/workflows/release.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..7626b0c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,28 @@ +name: Publish Python 🐍 distribution 📦 to PyPI upon new release + +on: + release: + types: [created] + +jobs: + build-n-publish: + name: Build and publish Python 🐍 distributions 📦 to PyPI + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* From abf37793bb226e7b1a4be044117942a41fc5cce8 Mon Sep 17 00:00:00 2001 From: sina-mansour Date: Mon, 7 Aug 2023 18:19:20 +0800 Subject: [PATCH 7/8] created a new release to test the automation scripts --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ac79dd7..9491064 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setuptools.setup( name="Connectome_Spatial_Smoothing", - version="0.1.3", + version="0.1.4", author="Sina Mansour L.", author_email="sina.mansour.lakouraj@gmail.com", description="Connectome Spatial Smoothing", From 2a97bbaad6b1b38efec235698e64055f3f4f1296 Mon Sep 17 00:00:00 2001 From: sina-mansour Date: Mon, 7 Aug 2023 18:25:00 +0800 Subject: [PATCH 8/8] fixed a bug in suppressing verbosity --- code/Connectome_Spatial_Smoothing/CSS.py | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/code/Connectome_Spatial_Smoothing/CSS.py b/code/Connectome_Spatial_Smoothing/CSS.py index e899c87..9921401 100644 --- a/code/Connectome_Spatial_Smoothing/CSS.py +++ b/code/Connectome_Spatial_Smoothing/CSS.py @@ -45,22 +45,22 @@ def _load_sparse(file_path): def _time_str(mode='abs', base=None): - if _verbose: - if mode == 'rel': - return str(datetime.timedelta(seconds=(time.time() - base))) - if mode == 'raw': - return time.time() - if mode == 'abs': - return time.asctime(time.localtime(time.time())) + if mode == 'rel': + return str(datetime.timedelta(seconds=(time.time() - base))) + if mode == 'raw': + return time.time() + if mode == 'abs': + return time.asctime(time.localtime(time.time())) def _print_log(message, mode='info'): - if mode == 'info': - print ('{}: \033[0;32m[INFO]\033[0m {}'.format(_time_str(), message)) - if mode == 'err': - print ('{}: \033[0;31m[ERROR]\033[0m {}'.format(_time_str(), message)) - quit() - sys.stdout.flush() + if _verbose: + if mode == 'info': + print ('{}: \033[0;32m[INFO]\033[0m {}'.format(_time_str(), message)) + if mode == 'err': + print ('{}: \033[0;31m[ERROR]\033[0m {}'.format(_time_str(), message)) + quit() + sys.stdout.flush() def _handle_process_with_que(que, func, args, kwds):