Skip to content

Handle zero-variance ROIs in correlation matrix#295

Merged
nx10 merged 1 commit into
mainfrom
fix/correlation-zero-variance-warning
Apr 11, 2026
Merged

Handle zero-variance ROIs in correlation matrix#295
nx10 merged 1 commit into
mainfrom
fix/correlation-zero-variance-warning

Conversation

@nx10
Copy link
Copy Markdown
Contributor

@nx10 nx10 commented Apr 9, 2026

Summary

  • Zero-variance (constant signal) ROIs now get NaN correlations instead of triggering a numpy RuntimeWarning: invalid value encountered in divide
  • Diagonal is always 1.0, even for constant ROIs
  • Logs a warning when zero-variance ROIs are detected

Closes #261

Test plan

  • Unit test: mixed valid/constant ROIs produce NaN off-diagonal, no RuntimeWarning raised
  • Unit test: all-constant ROIs produce NaN off-diagonal, 1.0 diagonal
  • Existing correlation tests still pass

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 9, 2026

Coverage

Coverage Report
FileStmtsMissCoverMissing
rbc
   __init__.py10100% 
   context.py25868%70, 75–77, 79–80, 93–94
   metadata.py560100% 
rbc/bids
   __init__.py90100% 
   _schema.py585499%776, 782, 790, 1101
   anatomical.py24387%44, 47–48
   builder.py72790%233–235, 362, 364–365, 386
   functional.py42588%46–49, 84
   longitudinal.py250100% 
   metrics.py23195%44
   qc.py170100% 
   query.py674237%103–107, 121–125, 127–128, 130–135, 137, 139, 153, 159–165, 198, 207, 209–216, 225, 257, 266–267
   session.py470100% 
rbc/cli
   __init__.py10100% 
   all.py49295%84, 109
   anatomical.py25292%47, 63
   base.py71987%56, 62, 123–125, 131–133, 156
   functional.py33293%67, 87
   longitudinal.py27292%46, 63
   main.py420100% 
   metrics.py42295%77, 95
   qc.py25292%45, 61
rbc/core
   __init__.py30100% 
   common.py261253%43–45, 62–70
   fileops.py27485%69–72
   fsl2itk.py420100% 
   nifti.py192597%236–237, 244–245, 524
   niwrap.py56198%58
rbc/core/anatomical
   __init__.py40100% 
   registration.py15473%59, 151, 166, 183
   segmentation.py24866%64, 74–76, 92, 114, 125, 141
rbc/core/functional
   __init__.py130100% 
   coregistration.py7271%44, 55
   despiking.py7357%32, 36–37
   distortion.py1304069%269–271, 321, 324, 332–335, 341–346, 349, 352–353, 356, 365–369, 375–376, 387–388, 391, 397, 443–444, 447, 455, 461, 470–471, 474, 484, 491
   erosion.py32196%50
   initialization.py9455%35, 42–43, 63
   masking.py342526%53, 55–56, 58–59, 62–65, 69, 91, 134, 183, 197, 208, 223, 233, 249, 258, 271, 285, 296, 306, 319, 328
   motion.py573735%62, 64–67, 69, 71, 73, 76–77, 83–84, 86–87, 95–97, 99, 102, 105, 107, 124–125, 135–138, 159, 169, 171–172, 175, 177–179, 181, 183
   nuisance.py816025%78, 80–85, 87, 89–90, 93, 96–98, 100–102, 104–110, 112–116, 118, 163, 165, 167, 170–171, 173–175, 178, 181–182, 185–187, 190–193, 197, 203–205, 207, 235, 243, 269, 278, 307, 316, 322
   regressors.py89693%163, 193, 325–328
   resampling.py544320%37–42, 74–76, 78, 80–81, 85–87, 90, 93, 105, 107–108, 112, 114, 150–152, 154–155, 159, 161–162, 167–169, 173–174, 177, 180, 187, 199, 201–202, 207, 209
   timing.py161131%46–47, 49–53, 58, 60, 66–67
rbc/core/longitudinal
   __init__.py10100% 
   transform.py46784%106–107, 165–168, 170
rbc/core/metrics
   __init__.py30100% 
   alff.py90198%265
   reho.py660100% 
   smoothing.py7357%36, 42–43
   standardization.py271159%64, 66–68, 70, 72–75, 77–78
   timeseries.py70198%147
rbc/core/qc
   __init__.py60100% 
   dvars.py260100% 
   motion.py310100% 
   registration.py410100% 
   xcp.py410100% 
rbc/orchestration
   __init__.py32293%90, 93
   all.py41978%131–132, 137, 145, 153–154, 171, 173–174
   anatomical.py372240%49–52, 57–58, 60–63, 85–87, 89–90, 94, 101, 104, 109–110, 116, 118
   functional.py411270%124–126, 128–129, 133, 139, 142, 147–148, 157, 159
   longitudinal.py56198%150
   metrics.py463034%32–35, 38–40, 67, 75–76, 100–102, 104–106, 110, 118–121, 123–124, 130–132, 137, 145, 152, 154
   qc.py340100% 
rbc/workflows
   __init__.py100100% 
   anatomical.py471959%90–93, 97–102, 107, 177–180, 182–184, 188
   functional.py985642%113–114, 122, 127–128, 136, 207–208, 211–212, 215–216, 219, 222–225, 235–237, 247–248, 251, 254, 257–258, 266–267, 274–275, 282–283, 290–291, 294–296, 299–302, 314–315, 327, 329–332, 335–336, 345–346, 354, 361, 430, 436
   metrics.py411856%80, 83–84, 93–94, 99–102, 105–108, 112–115, 119
   qc.py553438%88–89, 92–93, 96, 99, 102–107, 110, 119–121, 125–128, 130–134, 136–137, 139–141, 144, 161, 167, 169
rbc_resources
   __init__.py380100% 
TOTAL325758382% 

Tests Skipped Failures Errors Time
732 0 💤 0 ❌ 0 🔥 10.514s ⏱️

Skip zero-variance ROIs when computing np.corrcoef to avoid the
RuntimeWarning about division by zero. Affected off-diagonal entries
are set to NaN; the diagonal is always 1.0. A warning is logged
identifying how many ROIs were constant.

Closes #261
@nx10 nx10 force-pushed the fix/correlation-zero-variance-warning branch from a08d945 to 53cc5be Compare April 10, 2026 06:51
@nx10 nx10 merged commit 272a825 into main Apr 11, 2026
8 checks passed
@nx10 nx10 deleted the fix/correlation-zero-variance-warning branch April 11, 2026 04:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RuntimeWarning: invalid value encountered in divide

2 participants