Analysis Toolbox#
Analysis Toolbox Demo¶
This notebook demonstrates post-fit analysis helpers: ROI statistics, ROI timecourses, and group-level comparisons. The example synthesizes a small batch study, so it runs without bundled datasets.
[1]:
from pathlib import Path
import json
import shutil
import numpy as np
import matplotlib.pyplot as plt
from mrax.analysis import ROI, collect_roi_stats, extract_timecourse, analyze_groups
from mrax.core.batch import run_batch_studies
from mrax.core.synthetic import make_example_suite
from mrax.data_struct import Quantity, Study, load_study_results
Run a small batch study¶
Create four synthetic subjects, fit a T1 inversion-recovery model for each subject, and persist the generated results under tmp/analysis_toolbox_demo.
[2]:
demo_root = Path.cwd() / "tmp" / "analysis_toolbox_demo"
inputs_root = demo_root / "inputs"
outputs_root = demo_root / "outputs"
for path in (inputs_root, outputs_root):
if path.exists():
shutil.rmtree(path)
path.mkdir(parents=True, exist_ok=True)
subjects = [
("control_01", 0, "control"),
("control_02", 1, "control"),
("treated_01", 2, "treated"),
("treated_02", 3, "treated"),
]
for name, seed, group in subjects:
study_dir = inputs_root / name
study_dir.mkdir(parents=True, exist_ok=True)
(study_dir / "config.json").write_text(json.dumps({"seed": seed, "group": group}))
def loader(study_dir: Path):
cfg = json.loads((study_dir / "config.json").read_text())
examples = make_example_suite(noise_level=0.03, seed=cfg["seed"])[:1]
study_globals = {"field_strength_mhz": Quantity(400.0, "MHz")}
return Study.from_examples(examples, study_globals=study_globals), {"config": cfg}
summaries = run_batch_studies(
studies_root=inputs_root,
study_loader=loader,
output_root=outputs_root,
analysis_kwargs={"num_steps": 3, "step_size": 0.02},
)
summaries
[2]:
[{'study_name': 'control_01',
'manifest_path': PosixPath('/tmp/mrax-notebook-smoke/tmp/analysis_toolbox_demo/outputs/control_01/study_manifest.json'),
'results': [{'name': 't1_ir',
'model': 't1_ir',
'fields': {'amplitude': Quantity(values=Array([[0.68209094, 0.68224174, 0.6835417 , 0.6861043 , 0.68232936,
0.6828738 , 0.6820199 , 0.6835348 , 0.6820076 , 0.6838535 ,
0.6821099 , 0.68606627, 0.6823191 , 0.68227303, 0.6821362 ,
0.68248117],
[0.7430966 , 0.7430551 , 0.7426947 , 0.715351 , 0.68526715,
0.68195516, 0.68180376, 0.68175155, 0.6817051 , 0.6817301 ,
0.68183374, 0.6818913 , 0.68316513, 0.68289655, 0.72453564,
0.6853528 ],
[0.7431159 , 0.74310654, 0.7431274 , 0.7429968 , 0.6829904 ,
0.6817659 , 0.6816841 , 0.6816497 , 0.681646 , 0.6816479 ,
0.6816673 , 0.681732 , 0.6820277 , 0.6840507 , 0.7336869 ,
0.7423251 ],
[0.743139 , 0.74313307, 0.7431121 , 0.7431135 , 0.7401124 ,
0.6817257 , 0.6816459 , 0.6816228 , 0.6816217 , 0.681634 ,
0.6816503 , 0.6817084 , 0.68205976, 0.69966215, 0.74276143,
0.7425461 ],
[0.7431496 , 0.7431441 , 0.74312794, 0.74303895, 0.74270695,
0.6818746 , 0.6816437 , 0.6816312 , 0.681623 , 0.6816238 ,
0.68164027, 0.68169117, 0.6819515 , 0.68580484, 0.73335654,
0.7408031 ],
[0.7431452 , 0.74314225, 0.74313277, 0.743066 , 0.73993075,
0.68217987, 0.6816532 , 0.6816411 , 0.68162644, 0.6816286 ,
0.6816521 , 0.68168825, 0.6817677 , 0.68207175, 0.68308324,
0.7064828 ],
[0.7431378 , 0.74313027, 0.74311626, 0.74308586, 0.7430133 ,
0.6839724 , 0.68179494, 0.68167686, 0.6816574 , 0.6816509 ,
0.6816626 , 0.68169695, 0.6817174 , 0.6816542 , 0.6817295 ,
0.6820693 ],
[0.74309283, 0.7430971 , 0.74307835, 0.7430046 , 0.74300927,
0.7428877 , 0.6827399 , 0.68199426, 0.6818232 , 0.68170184,
0.681732 , 0.68166983, 0.6816904 , 0.6816737 , 0.68164635,
0.6816524 ],
[0.74268305, 0.74285424, 0.7428627 , 0.7430068 , 0.74308497,
0.7430924 , 0.7430648 , 0.7429047 , 0.68234295, 0.6820088 ,
0.68174464, 0.68170226, 0.6816719 , 0.68165505, 0.6816522 ,
0.6816001 ],
[0.6820593 , 0.6857469 , 0.7412452 , 0.74295425, 0.7430819 ,
0.74309504, 0.7431188 , 0.74310315, 0.7430316 , 0.7120217 ,
0.6819575 , 0.6816913 , 0.68166226, 0.6816227 , 0.68162066,
0.6816158 ],
[0.6816944 , 0.6817793 , 0.68198496, 0.7413331 , 0.7430636 ,
0.7430702 , 0.7431282 , 0.74314004, 0.7431251 , 0.7429289 ,
0.68243366, 0.6817075 , 0.6816401 , 0.68162125, 0.6816098 ,
0.6816091 ],
[0.6816782 , 0.6816629 , 0.68178725, 0.68317 , 0.74303055,
0.74313307, 0.7431388 , 0.7431503 , 0.7431256 , 0.7430916 ,
0.6987384 , 0.6817765 , 0.6816399 , 0.68162584, 0.68161064,
0.6816029 ],
[0.6816719 , 0.68165964, 0.6818252 , 0.68242776, 0.74303496,
0.743112 , 0.7431446 , 0.7431435 , 0.7431302 , 0.7430827 ,
0.7396205 , 0.68181455, 0.6816685 , 0.68162394, 0.68161243,
0.68160504],
[0.68166906, 0.6816749 , 0.6817141 , 0.6863515 , 0.74027157,
0.7430819 , 0.7431213 , 0.74312514, 0.74311996, 0.7430243 ,
0.68383425, 0.6817812 , 0.6817007 , 0.6816423 , 0.6816262 ,
0.6816244 ],
[0.68184483, 0.681838 , 0.68178993, 0.68456984, 0.68959475,
0.7418566 , 0.7428324 , 0.7430257 , 0.74152803, 0.74035823,
0.68271613, 0.6820309 , 0.6817781 , 0.68173194, 0.68167466,
0.6816559 ],
[0.6827251 , 0.68281454, 0.6824246 , 0.68618023, 0.6822656 ,
0.68244934, 0.68219686, 0.6829403 , 0.6820001 , 0.68501204,
0.6825542 , 0.68416804, 0.68326324, 0.6830336 , 0.6824102 ,
0.6824026 ]], dtype=float32), si_unit='1'),
't1': Quantity(values=Array([[2451.0042, 2450.9924, 2451.019 , 2451.067 , 2450.9758, 2451.0269,
2450.9536, 2451.019 , 2450.967 , 2451. , 2450.9907, 2451.0186,
2450.9875, 2451.0293, 2450.9902, 2450.9543],
[2450.6682, 2450.6782, 2450.6865, 2450.9756, 2451.117 , 2450.959 ,
2450.9565, 2450.9448, 2450.941 , 2450.937 , 2450.977 , 2450.9465,
2451.001 , 2450.982 , 2450.7292, 2451.0247],
[2597.483 , 2557.1414, 2450.6584, 2450.6804, 2451.0735, 2450.9758,
2450.927 , 2450.9053, 2450.8936, 2450.9014, 2450.903 , 2450.9592,
2450.958 , 2451.067 , 2450.6934, 2450.6833],
[2598.8752, 2598.8071, 2596.972 , 2450.6743, 2450.6846, 2450.9487,
2450.907 , 2450.876 , 2450.8782, 2450.8914, 2450.911 , 2450.9556,
2451.181 , 2451.4946, 2450.6675, 2450.66 ],
[2599.0725, 2599.0088, 2598.7795, 2586.176 , 2450.6772, 2450.989 ,
2450.8948, 2450.8818, 2450.8774, 2450.8809, 2450.91 , 2450.9478,
2451.3464, 2474.6184, 2597.622 , 2596.6504],
[2599.0647, 2599.026 , 2598.9653, 2597.409 , 2450.676 , 2451.117 ,
2450.927 , 2450.896 , 2450.8928, 2450.8853, 2450.9182, 2451.0535,
2451.7002, 2599.3315, 2599.2295, 2598.9407],
[2599.025 , 2598.994 , 2598.8833, 2598.3318, 2450.6565, 2451.1584,
2450.9744, 2450.9192, 2450.947 , 2450.9158, 2450.947 , 2451.038 ,
2452.4092, 2599.3352, 2599.2078, 2599.2068],
[2598.74 , 2598.7803, 2598.531 , 2595.6448, 2450.6572, 2450.6738,
2451.0337, 2450.982 , 2450.974 , 2450.9292, 2451.005 , 2451.0403,
2452.1953, 2490.0293, 2599.2485, 2599.2266],
[2593.291 , 2593.9888, 2596.794 , 2585.4006, 2450.7188, 2450.666 ,
2450.6763, 2450.6865, 2450.9702, 2450.97 , 2450.9998, 2451.1274,
2452.213 , 2458.0876, 2460.9697, 2594.822 ],
[2452.127 , 2453.8057, 2450.7751, 2450.6821, 2450.67 , 2450.6587,
2450.6584, 2450.68 , 2450.6816, 2450.948 , 2451.0796, 2451.1028,
2451.181 , 2451.0474, 2451.1313, 2451.228 ],
[2451.0676, 2451.1035, 2451.64 , 2450.676 , 2450.6567, 2544.4973,
2450.665 , 2450.673 , 2450.6794, 2450.6855, 2451.0452, 2451.0022,
2450.9883, 2450.9631, 2450.968 , 2450.9502],
[2450.9895, 2451.0176, 2451.144 , 2451.2048, 2450.664 , 2450.7876,
2450.661 , 2450.6614, 2450.6804, 2450.676 , 2451.0825, 2451.032 ,
2450.9453, 2450.9583, 2450.9197, 2450.892 ],
[2450.9844, 2450.965 , 2451.1003, 2451.157 , 2450.665 , 2450.6738,
2450.6838, 2450.66 , 2450.666 , 2450.6812, 2450.6907, 2450.9827,
2450.9578, 2450.904 , 2450.893 , 2450.8838],
[2450.943 , 2450.9353, 2450.993 , 2451.0217, 2450.6921, 2450.6777,
2450.6792, 2450.6748, 2450.674 , 2450.686 , 2451.046 , 2450.964 ,
2450.9248, 2450.913 , 2450.8914, 2450.8958],
[2450.9949, 2450.9749, 2450.9807, 2451.0176, 2451.0493, 2450.6926,
2450.6877, 2450.6858, 2450.69 , 2450.6912, 2450.9695, 2450.9937,
2450.9436, 2450.9377, 2450.9043, 2450.9092],
[2450.9827, 2450.983 , 2451.0076, 2451.0732, 2450.9792, 2451.0076,
2450.9675, 2450.99 , 2450.9287, 2450.9658, 2451.0012, 2451.0393,
2451.0032, 2450.983 , 2450.9822, 2450.962 ]], dtype=float32), si_unit='ms')},
'loss_history': [0.15132774412631989,
0.14381380379199982,
0.1369260996580124],
'cached': False}],
'metadata': {'config': {'seed': 0, 'group': 'control'}},
'study_dir': PosixPath('/tmp/mrax-notebook-smoke/tmp/analysis_toolbox_demo/inputs/control_01')},
{'study_name': 'control_02',
'manifest_path': PosixPath('/tmp/mrax-notebook-smoke/tmp/analysis_toolbox_demo/outputs/control_02/study_manifest.json'),
'results': [{'name': 't1_ir',
'model': 't1_ir',
'fields': {'amplitude': Quantity(values=Array([[0.6822252 , 0.6823839 , 0.6839408 , 0.68228877, 0.6820798 ,
0.6831264 , 0.6822702 , 0.6823908 , 0.6822631 , 0.6846213 ,
0.6821853 , 0.68461674, 0.68264514, 0.682621 , 0.6822236 ,
0.6826585 ],
[0.7431072 , 0.74310666, 0.74300545, 0.6925658 , 0.6845981 ,
0.68209374, 0.6818051 , 0.6817074 , 0.68170273, 0.68179005,
0.6817736 , 0.681787 , 0.6820992 , 0.6866397 , 0.71368307,
0.7423841 ],
[0.743111 , 0.7431143 , 0.74312735, 0.7430483 , 0.6832909 ,
0.6818545 , 0.6816737 , 0.6816567 , 0.68164337, 0.6816542 ,
0.6816691 , 0.6819223 , 0.68235606, 0.68482894, 0.7428077 ,
0.7424368 ],
[0.74314046, 0.74313474, 0.743111 , 0.743049 , 0.72677654,
0.6817443 , 0.6816455 , 0.6816309 , 0.68162054, 0.68163717,
0.6816423 , 0.68170744, 0.68193036, 0.69467705, 0.74138117,
0.74220234],
[0.74314505, 0.74314094, 0.7431274 , 0.7430745 , 0.7427708 ,
0.68173534, 0.6816522 , 0.6816261 , 0.68162555, 0.6816292 ,
0.6816449 , 0.6816919 , 0.6818061 , 0.6859464 , 0.7378271 ,
0.7373897 ],
[0.74314433, 0.7431437 , 0.74312896, 0.74307674, 0.74279183,
0.68227786, 0.68167865, 0.6816443 , 0.6816226 , 0.6816236 ,
0.68163186, 0.6816626 , 0.6818772 , 0.6827852 , 0.6863788 ,
0.7057801 ],
[0.743133 , 0.7431266 , 0.7431236 , 0.7430445 , 0.7430071 ,
0.71171623, 0.68173295, 0.6816723 , 0.68167 , 0.6816453 ,
0.6816655 , 0.6816939 , 0.6817345 , 0.68169075, 0.6817215 ,
0.68185526],
[0.7431084 , 0.74308354, 0.74309754, 0.7430374 , 0.7430007 ,
0.74277085, 0.682819 , 0.68199825, 0.681797 , 0.68167454,
0.6816888 , 0.6816733 , 0.68171257, 0.6816315 , 0.6816421 ,
0.6816557 ],
[0.7424498 , 0.74273425, 0.74295163, 0.74290705, 0.7430694 ,
0.7430976 , 0.7429578 , 0.7424428 , 0.70971715, 0.6821044 ,
0.68170065, 0.68169785, 0.6816567 , 0.68165684, 0.6816389 ,
0.6816362 ],
[0.6819688 , 0.6824943 , 0.7384075 , 0.7429611 , 0.74307823,
0.7431027 , 0.74311346, 0.74312115, 0.7430394 , 0.74240345,
0.68195426, 0.6817086 , 0.68164223, 0.68164104, 0.68161803,
0.6816171 ],
[0.68169826, 0.68172234, 0.68227935, 0.692978 , 0.743104 ,
0.7430871 , 0.74313617, 0.74313915, 0.743124 , 0.74280775,
0.6827494 , 0.6817308 , 0.6816592 , 0.68161684, 0.6816176 ,
0.68160653],
[0.6816644 , 0.68169355, 0.68178177, 0.699271 , 0.74304515,
0.74313074, 0.743145 , 0.7431379 , 0.743137 , 0.7430318 ,
0.6849173 , 0.6817845 , 0.6816407 , 0.6816165 , 0.68161255,
0.6816023 ],
[0.6816688 , 0.68167526, 0.68175566, 0.6870008 , 0.7430245 ,
0.74312943, 0.7431429 , 0.74314153, 0.7431396 , 0.7430812 ,
0.71757215, 0.68178266, 0.6816769 , 0.68162894, 0.6816141 ,
0.68160814],
[0.6816895 , 0.68169343, 0.6817601 , 0.68219596, 0.74291927,
0.74308765, 0.74310994, 0.7431202 , 0.743093 , 0.7429749 ,
0.7072856 , 0.6819312 , 0.6816661 , 0.6816423 , 0.68162847,
0.68162113],
[0.68181974, 0.6819553 , 0.6819781 , 0.6821021 , 0.6834799 ,
0.7196619 , 0.74258935, 0.74301046, 0.7428989 , 0.73720545,
0.6833024 , 0.6820794 , 0.6817877 , 0.6817106 , 0.6816779 ,
0.68166465],
[0.6823212 , 0.68455577, 0.68242085, 0.6825844 , 0.6928078 ,
0.6820986 , 0.6825319 , 0.68278486, 0.68217915, 0.68345153,
0.6837263 , 0.6830403 , 0.6821558 , 0.68209946, 0.68222785,
0.68371826]], dtype=float32), si_unit='1'),
't1': Quantity(values=Array([[2450.965 , 2450.9946, 2450.9976, 2450.9749, 2450.9722, 2451.0132,
2450.9897, 2451.0005, 2450.9792, 2451.0005, 2450.974 , 2451.0134,
2450.9675, 2450.9976, 2450.9963, 2451.0002],
[2450.6736, 2450.6743, 2450.6821, 2451.0254, 2451.0364, 2451.03 ,
2450.931 , 2450.9287, 2450.91 , 2450.9375, 2450.9575, 2450.926 ,
2450.9497, 2451.0083, 2450.9514, 2450.688 ],
[2596.9404, 2595.1887, 2450.66 , 2450.666 , 2451.0134, 2450.9907,
2450.9136, 2450.9065, 2450.898 , 2450.8923, 2450.9148, 2450.983 ,
2451.0825, 2451.0261, 2450.6777, 2450.6816],
[2598.955 , 2598.8325, 2597.8748, 2529.9014, 2450.7131, 2450.9536,
2450.907 , 2450.8887, 2450.8794, 2450.8977, 2450.892 , 2450.9546,
2451.0713, 2451.4368, 2450.6567, 2450.664 ],
[2599.041 , 2598.999 , 2598.7866, 2596.2937, 2450.6716, 2450.9885,
2450.9175, 2450.8816, 2450.89 , 2450.8796, 2450.9048, 2450.9663,
2451.148 , 2506.513 , 2596.9832, 2597.5386],
[2599.0457, 2599.0496, 2598.9314, 2598.4412, 2450.6606, 2451.1008,
2450.9282, 2450.898 , 2450.883 , 2450.8826, 2450.893 , 2450.9773,
2451.7725, 2599.2678, 2599.212 , 2599.149 ],
[2598.9727, 2598.9292, 2598.8762, 2596.9866, 2450.6594, 2451.1597,
2450.9358, 2450.9077, 2450.8967, 2450.921 , 2450.9392, 2451.0974,
2452.5295, 2599.3088, 2599.2422, 2599.208 ],
[2598.819 , 2598.4116, 2598.8376, 2598.1492, 2450.6565, 2450.6702,
2451.0315, 2450.9539, 2450.9583, 2450.9307, 2450.997 , 2451.067 ,
2451.8914, 2599.3115, 2599.267 , 2599.2358],
[2572.8503, 2582.2822, 2595.3599, 2595.1042, 2450.682 , 2452.3845,
2450.6848, 2450.6858, 2450.9575, 2450.9756, 2451.0015, 2451.2502,
2451.2312, 2453.3955, 2452.8457, 2503.9285],
[2451.2607, 2451.6152, 2450.6865, 2451.014 , 2451.772 , 2450.6572,
2450.6704, 2450.6787, 2450.6863, 2450.6848, 2451.0657, 2451.1816,
2451.0886, 2451.4436, 2451.301 , 2451.2334],
[2451.084 , 2451.1143, 2451.3718, 2451.4612, 2450.6584, 2536.6719,
2450.6587, 2450.6643, 2450.68 , 2450.6865, 2451.0356, 2451.0405,
2451.1025, 2450.9531, 2451.0242, 2450.9397],
[2450.9758, 2450.9998, 2451.0679, 2452.1614, 2450.6667, 2450.659 ,
2450.6777, 2450.6577, 2450.67 , 2450.6882, 2451.0198, 2451.0417,
2450.9426, 2450.9226, 2450.9197, 2450.8906],
[2450.9878, 2450.997 , 2451.0293, 2451.2158, 2450.6755, 2450.661 ,
2450.6572, 2450.663 , 2450.6777, 2450.6836, 2450.7717, 2450.9983,
2450.9614, 2450.8992, 2450.8953, 2450.892 ],
[2450.9546, 2450.971 , 2450.971 , 2451.0198, 2450.686 , 2450.6821,
2450.6738, 2450.6765, 2450.6838, 2450.684 , 2450.943 , 2450.9836,
2450.9133, 2450.9058, 2450.8904, 2450.8882],
[2450.974 , 2451.0117, 2451.0042, 2451.0037, 2450.9958, 2450.7583,
2450.689 , 2450.6892, 2450.689 , 2450.6936, 2450.9797, 2450.9675,
2450.9697, 2450.934 , 2450.9277, 2450.9214],
[2450.9946, 2450.9814, 2451.0076, 2450.9702, 2451.0415, 2450.9692,
2450.9797, 2450.9941, 2450.9702, 2451.0032, 2450.9805, 2451.028 ,
2450.9587, 2450.964 , 2450.9739, 2451.0242]], dtype=float32), si_unit='ms')},
'loss_history': [0.150870680809021,
0.14339159429073334,
0.13653187453746796],
'cached': False}],
'metadata': {'config': {'seed': 1, 'group': 'control'}},
'study_dir': PosixPath('/tmp/mrax-notebook-smoke/tmp/analysis_toolbox_demo/inputs/control_02')},
{'study_name': 'treated_01',
'manifest_path': PosixPath('/tmp/mrax-notebook-smoke/tmp/analysis_toolbox_demo/outputs/treated_01/study_manifest.json'),
'results': [{'name': 't1_ir',
'model': 't1_ir',
'fields': {'amplitude': Quantity(values=Array([[0.6840635 , 0.68246615, 0.6824025 , 0.6823969 , 0.68219155,
0.6859856 , 0.68218327, 0.68274003, 0.68375576, 0.68296057,
0.68260694, 0.6940091 , 0.6822574 , 0.6836015 , 0.6823665 ,
0.68184596],
[0.74310863, 0.74307024, 0.74283046, 0.7427845 , 0.6832082 ,
0.68192667, 0.6817856 , 0.68172425, 0.68167526, 0.68175465,
0.6817727 , 0.68201536, 0.6819208 , 0.68260914, 0.69655573,
0.68653774],
[0.7431198 , 0.7431408 , 0.74308574, 0.74308497, 0.7163158 ,
0.68178153, 0.68166167, 0.68164635, 0.68164593, 0.68165547,
0.6817036 , 0.6817828 , 0.6820144 , 0.695111 , 0.74243337,
0.74258995],
[0.74313664, 0.74313664, 0.74311763, 0.743121 , 0.69347614,
0.6817588 , 0.6816627 , 0.68162507, 0.681626 , 0.6816272 ,
0.68165946, 0.681688 , 0.6825288 , 0.6866009 , 0.74284095,
0.71099097],
[0.7431459 , 0.743142 , 0.7431288 , 0.74306506, 0.74271953,
0.6817773 , 0.68164766, 0.6816255 , 0.6816238 , 0.6816261 ,
0.6816576 , 0.6817054 , 0.6818784 , 0.6836108 , 0.7415086 ,
0.7423605 ],
[0.7431446 , 0.74314034, 0.74313146, 0.7430735 , 0.74300826,
0.68218046, 0.6816794 , 0.6816329 , 0.6816322 , 0.68163204,
0.6816404 , 0.681662 , 0.68176955, 0.6816962 , 0.68202084,
0.7130929 ],
[0.743135 , 0.74313396, 0.74311066, 0.7430717 , 0.743012 ,
0.6835617 , 0.681735 , 0.68167424, 0.68166286, 0.68166465,
0.6816571 , 0.68166894, 0.6817153 , 0.6816774 , 0.68187755,
0.68243366],
[0.7431015 , 0.7431064 , 0.7430737 , 0.743019 , 0.74304515,
0.74279356, 0.6842172 , 0.68182147, 0.68175715, 0.6817733 ,
0.6817072 , 0.68166715, 0.6816939 , 0.68163335, 0.6816291 ,
0.6816552 ],
[0.74287397, 0.7424762 , 0.74284005, 0.74287313, 0.7430483 ,
0.7430072 , 0.7428921 , 0.70976615, 0.6828131 , 0.68191016,
0.6817669 , 0.6816976 , 0.6816705 , 0.6816583 , 0.6816383 ,
0.6816017 ],
[0.6828026 , 0.6848309 , 0.7176072 , 0.7427187 , 0.74308777,
0.74305534, 0.7431299 , 0.7431133 , 0.7429568 , 0.7180792 ,
0.68228 , 0.6817193 , 0.68164736, 0.68162495, 0.68161565,
0.6816161 ],
[0.68169355, 0.68174034, 0.6819078 , 0.7165696 , 0.7430512 ,
0.743127 , 0.7431362 , 0.7431384 , 0.7431311 , 0.74306774,
0.68236923, 0.68173504, 0.6816384 , 0.6816253 , 0.6816088 ,
0.6816075 ],
[0.6816504 , 0.6816575 , 0.6817962 , 0.6823734 , 0.7430882 ,
0.74312824, 0.743113 , 0.7431478 , 0.74314284, 0.7430648 ,
0.74110776, 0.68176514, 0.681641 , 0.6816179 , 0.68161225,
0.6816039 ],
[0.68165284, 0.6816668 , 0.68172306, 0.69065 , 0.74162036,
0.74312806, 0.7431376 , 0.74313945, 0.74312645, 0.7430848 ,
0.72388333, 0.68177485, 0.6816497 , 0.68162644, 0.6816115 ,
0.6816093 ],
[0.68168014, 0.68168473, 0.681896 , 0.6824043 , 0.74072087,
0.74307877, 0.743118 , 0.7431275 , 0.74310255, 0.7430742 ,
0.6913082 , 0.6818626 , 0.6816873 , 0.6816535 , 0.6816231 ,
0.68162876],
[0.6817374 , 0.6817978 , 0.68193597, 0.68378305, 0.69661707,
0.7419625 , 0.74300665, 0.7428335 , 0.74252176, 0.7294907 ,
0.6839797 , 0.6819715 , 0.68173784, 0.68179655, 0.681662 ,
0.68167084],
[0.68310577, 0.68206555, 0.68204725, 0.68195146, 0.68435055,
0.6821535 , 0.6819756 , 0.68235797, 0.6820901 , 0.68230015,
0.6828375 , 0.6821874 , 0.68194205, 0.68281436, 0.68305475,
0.68334603]], dtype=float32), si_unit='1'),
't1': Quantity(values=Array([[2450.9875, 2451.0042, 2451.0015, 2450.982 , 2451.0002, 2451.0015,
2450.9775, 2451.0142, 2451.037 , 2451.0002, 2451.0125, 2451.0293,
2450.9858, 2450.9958, 2450.9783, 2450.9546],
[2450.6687, 2450.6836, 2450.684 , 2450.6873, 2451.0164, 2450.955 ,
2450.9475, 2450.9287, 2450.9092, 2450.9363, 2450.945 , 2450.9639,
2450.9646, 2450.9993, 2450.9956, 2451.0237],
[2597.7512, 2450.7615, 2568.751 , 2450.665 , 2450.7717, 2450.9426,
2450.9058, 2450.904 , 2450.8923, 2450.8933, 2450.9336, 2450.974 ,
2450.988 , 2451.0657, 2450.686 , 2450.6833],
[2598.7734, 2598.8787, 2598.5012, 2450.864 , 2451.1174, 2450.964 ,
2450.9128, 2450.889 , 2450.883 , 2450.883 , 2450.9375, 2450.955 ,
2451.185 , 2451.4702, 2450.658 , 2451.5806],
[2599.023 , 2598.9834, 2598.8347, 2596.9023, 2450.678 , 2450.982 ,
2450.9048, 2450.8765, 2450.8901, 2450.8875, 2450.9182, 2450.9675,
2451.2063, 2478.931 , 2596.5989, 2598.4702],
[2599.0432, 2599.028 , 2598.952 , 2598.0007, 2450.6594, 2451.0605,
2450.9304, 2450.8904, 2450.8926, 2450.8906, 2450.911 , 2450.9875,
2451.4753, 2594.1616, 2599.2627, 2598.9248],
[2599.0007, 2598.9897, 2598.7158, 2597.9233, 2450.6567, 2451.2097,
2450.9468, 2450.9163, 2450.9084, 2450.9297, 2450.949 , 2451.073 ,
2451.7476, 2599.2961, 2599.2158, 2599.1978],
[2598.8777, 2598.863 , 2598.616 , 2594.4778, 2450.6572, 2450.6577,
2451.0874, 2450.9521, 2450.9297, 2450.946 , 2451.0156, 2451.0452,
2452.2515, 2599.2903, 2599.2732, 2599.2168],
[2588.8704, 2515.1702, 2590.081 , 2591.7634, 2450.6978, 2450.6687,
2450.6848, 2450.947 , 2451.0076, 2450.9902, 2451.0684, 2451.1404,
2451.5 , 2470.1252, 2454.25 , 2599.171 ],
[2451.6245, 2452.4426, 2450.927 , 2450.7412, 2456.2043, 2590.2302,
2450.6587, 2450.6758, 2450.6882, 2450.7615, 2451.1575, 2451.145 ,
2451.1362, 2451.1404, 2451.1775, 2451.2708],
[2451.079 , 2451.0786, 2451.3218, 2451.2986, 2450.661 , 2451.279 ,
2450.6577, 2450.6675, 2450.666 , 2450.6755, 2451.0735, 2451.085 ,
2451.0322, 2451.0396, 2450.9458, 2450.9792],
[2450.967 , 2450.9766, 2451.1392, 2451.1453, 2450.6575, 2450.6572,
2563.1907, 2450.67 , 2450.665 , 2450.678 , 2450.685 , 2451.0293,
2451.0002, 2450.9248, 2450.9197, 2450.8987],
[2450.9521, 2450.9602, 2451.0422, 2451.2039, 2450.6865, 2450.6575,
2450.665 , 2450.6687, 2450.6804, 2450.6877, 2450.7332, 2450.9912,
2450.9175, 2450.91 , 2450.89 , 2450.8914],
[2450.9482, 2450.9424, 2451.0024, 2451.0425, 2450.6877, 2450.6826,
2450.6787, 2450.6807, 2450.6821, 2450.6833, 2451.0068, 2450.9587,
2450.9219, 2450.932 , 2450.8923, 2450.8987],
[2450.955 , 2450.9524, 2450.997 , 2451.0276, 2450.9934, 2450.6882,
2450.688 , 2450.6914, 2450.6912, 2450.7053, 2450.9998, 2450.9478,
2450.923 , 2450.9414, 2450.9053, 2450.9192],
[2451.0237, 2450.9744, 2451.0024, 2450.9663, 2451.043 , 2451.0002,
2450.9307, 2450.9863, 2450.9807, 2450.962 , 2451.0088, 2450.9568,
2450.9631, 2450.982 , 2450.9983, 2451.0154]], dtype=float32), si_unit='ms')},
'loss_history': [0.1519847810268402,
0.14443373680114746,
0.1375051885843277],
'cached': False}],
'metadata': {'config': {'seed': 2, 'group': 'treated'}},
'study_dir': PosixPath('/tmp/mrax-notebook-smoke/tmp/analysis_toolbox_demo/inputs/treated_01')},
{'study_name': 'treated_02',
'manifest_path': PosixPath('/tmp/mrax-notebook-smoke/tmp/analysis_toolbox_demo/outputs/treated_02/study_manifest.json'),
'results': [{'name': 't1_ir',
'model': 't1_ir',
'fields': {'amplitude': Quantity(values=Array([[0.6819282 , 0.6821133 , 0.6820945 , 0.68258524, 0.6831481 ,
0.68211824, 0.6823683 , 0.6821233 , 0.6837261 , 0.6821822 ,
0.6822014 , 0.6822707 , 0.6873775 , 0.6822371 , 0.68197894,
0.68229187],
[0.74310976, 0.7430717 , 0.74296534, 0.7413105 , 0.68234795,
0.68237644, 0.681757 , 0.6817129 , 0.68170804, 0.68171924,
0.68175286, 0.6820982 , 0.68249285, 0.7367408 , 0.7167938 ,
0.74241537],
[0.7431094 , 0.7431012 , 0.7431211 , 0.74307096, 0.7100313 ,
0.68181795, 0.6816567 , 0.681635 , 0.6816503 , 0.681659 ,
0.68169 , 0.6817444 , 0.6822094 , 0.68695635, 0.6949966 ,
0.7429936 ],
[0.74314034, 0.74313235, 0.7431151 , 0.7431215 , 0.6959359 ,
0.68174803, 0.68165904, 0.68163085, 0.6816202 , 0.6816269 ,
0.6816541 , 0.68168986, 0.6822395 , 0.6993946 , 0.73918563,
0.7428811 ],
[0.743148 , 0.74314237, 0.7431336 , 0.7430738 , 0.74189067,
0.6817358 , 0.6816418 , 0.68162155, 0.68163085, 0.68162715,
0.68164676, 0.6816921 , 0.68189776, 0.683156 , 0.74166566,
0.74158204],
[0.7431435 , 0.74314195, 0.7431219 , 0.7430674 , 0.74290943,
0.6820586 , 0.68168426, 0.68164724, 0.6816238 , 0.68163896,
0.6816453 , 0.6816638 , 0.68175536, 0.68174475, 0.6847813 ,
0.74007535],
[0.74313605, 0.74313074, 0.74312514, 0.74303955, 0.74306446,
0.68289053, 0.68175703, 0.6816816 , 0.6816431 , 0.6816524 ,
0.6816525 , 0.68167853, 0.6817513 , 0.68168956, 0.68185526,
0.6824597 ],
[0.7430965 , 0.7430842 , 0.7430801 , 0.7430206 , 0.74301827,
0.7425623 , 0.6901343 , 0.68189347, 0.6819251 , 0.68175477,
0.6817431 , 0.681685 , 0.6816719 , 0.6816359 , 0.68162847,
0.68164366],
[0.7428843 , 0.7427033 , 0.74290264, 0.7429037 , 0.7430729 ,
0.7430755 , 0.74300987, 0.73655576, 0.69262946, 0.6820481 ,
0.68176603, 0.68166953, 0.68166345, 0.6816533 , 0.6816446 ,
0.6816443 ],
[0.69634414, 0.6822409 , 0.7011271 , 0.7427899 , 0.74292254,
0.74310994, 0.74312896, 0.7431046 , 0.7429813 , 0.6878972 ,
0.6820877 , 0.68173265, 0.6816383 , 0.68163884, 0.68161905,
0.6816243 ],
[0.68175626, 0.6817678 , 0.68194526, 0.7428911 , 0.7430945 ,
0.7430793 , 0.74313956, 0.7431377 , 0.7431169 , 0.74297774,
0.682119 , 0.6816966 , 0.6816555 , 0.68162006, 0.68160754,
0.6816114 ],
[0.6816671 , 0.6816841 , 0.6817586 , 0.68763775, 0.7430784 ,
0.74313253, 0.7431427 , 0.7431448 , 0.74313587, 0.7430706 ,
0.7144781 , 0.68174994, 0.6816478 , 0.6816194 , 0.6816096 ,
0.6816074 ],
[0.68164545, 0.6816629 , 0.68178254, 0.6931603 , 0.7429813 ,
0.74311984, 0.7431188 , 0.7431396 , 0.74313194, 0.7430612 ,
0.7355741 , 0.6817853 , 0.6816387 , 0.681627 , 0.68161345,
0.6816081 ],
[0.6816836 , 0.6817001 , 0.6818009 , 0.6836951 , 0.7429817 ,
0.7430736 , 0.7431284 , 0.7431197 , 0.7431174 , 0.742898 ,
0.70832884, 0.68181854, 0.6817004 , 0.6816316 , 0.68163025,
0.6816242 ],
[0.6817742 , 0.68176675, 0.68192565, 0.68202 , 0.71891445,
0.74299794, 0.74269587, 0.74302965, 0.74305636, 0.73991597,
0.68362325, 0.6820194 , 0.6819398 , 0.6817013 , 0.6816793 ,
0.6816616 ],
[0.68232626, 0.68237925, 0.6822307 , 0.68230146, 0.6822261 ,
0.68212116, 0.68302226, 0.68253684, 0.6832022 , 0.6824918 ,
0.6825006 , 0.6820824 , 0.68236876, 0.6829198 , 0.6821655 ,
0.68327224]], dtype=float32), si_unit='1'),
't1': Quantity(values=Array([[2450.9714, 2450.9382, 2450.9402, 2450.983 , 2451.049 , 2450.9731,
2451.0266, 2450.9758, 2451.0283, 2450.9512, 2450.9646, 2450.9897,
2451.001 , 2450.947 , 2450.944 , 2450.9856],
[2450.68 , 2450.6812, 2450.6848, 2450.6882, 2450.9822, 2450.9722,
2450.9387, 2450.921 , 2450.971 , 2450.9233, 2450.942 , 2451.0002,
2450.992 , 2450.6934, 2450.7732, 2450.6877],
[2588.0947, 2596.4175, 2450.658 , 2450.671 , 2450.9539, 2450.9553,
2450.9175, 2450.8894, 2450.8936, 2450.9185, 2450.919 , 2450.9373,
2450.9963, 2451.0642, 2451.0725, 2450.6663],
[2598.9458, 2598.7795, 2598.1145, 2456.092 , 2451.0186, 2450.9785,
2450.915 , 2450.8882, 2450.8752, 2450.8794, 2450.9048, 2450.959 ,
2451.1548, 2451.318 , 2450.6716, 2450.6755],
[2599.0413, 2598.9988, 2598.8645, 2592.0054, 2450.6843, 2450.9724,
2450.8984, 2450.8818, 2450.902 , 2450.8787, 2450.909 , 2451.012 ,
2451.3728, 2486.6982, 2596.3757, 2598.3196],
[2599.0127, 2599.041 , 2598.8738, 2596.4758, 2450.6653, 2451.099 ,
2450.9414, 2450.895 , 2450.873 , 2450.9104, 2450.9326, 2450.9602,
2451.4463, 2598.8376, 2599.2224, 2598.765 ],
[2599.0127, 2598.9824, 2598.9304, 2596.341 , 2450.9502, 2451.158 ,
2450.9587, 2450.9197, 2450.9026, 2450.9026, 2450.9336, 2451.089 ,
2451.811 , 2599.3115, 2599.2168, 2599.2021],
[2598.7896, 2598.5784, 2598.617 , 2575.9834, 2450.6577, 2450.6782,
2451.0479, 2450.9773, 2450.9636, 2450.9656, 2451.0042, 2451.1394,
2451.6816, 2599.2522, 2599.2686, 2599.2375],
[2595.6826, 2593.777 , 2592.9644, 2555.3313, 2450.9253, 2450.6616,
2450.6765, 2450.6963, 2451.0198, 2450.9941, 2451.022 , 2451.0525,
2451.388 , 2452.827 , 2487.021 , 2479.443 ],
[2455.5752, 2451.7288, 2452.2415, 2559.8303, 2555.9146, 2450.6914,
2450.663 , 2450.678 , 2450.689 , 2450.9958, 2451.2095, 2451.1497,
2451.0784, 2451.3125, 2451.4062, 2451.2473],
[2451.2664, 2451.14 , 2451.2551, 2450.66 , 2450.7732, 2577.148 ,
2450.665 , 2450.6638, 2450.6816, 2450.6848, 2451.046 , 2451.0542,
2451.0293, 2450.9736, 2450.9417, 2451.008 ],
[2451.0078, 2451.0298, 2451.2124, 2451.6052, 2450.6665, 2450.6975,
2450.6606, 2450.6665, 2450.676 , 2450.6807, 2450.7998, 2451.0024,
2450.949 , 2450.9336, 2450.9087, 2450.893 ],
[2450.945 , 2450.9631, 2451.0513, 2451.1985, 2450.674 , 2450.6687,
2537.5068, 2450.6716, 2450.6816, 2450.685 , 2450.6921, 2450.968 ,
2450.9197, 2450.9187, 2450.8818, 2450.893 ],
[2450.9492, 2450.9446, 2450.9868, 2451.1123, 2450.6843, 2450.6846,
2450.6694, 2450.6838, 2450.6804, 2450.689 , 2450.932 , 2450.9758,
2450.931 , 2450.911 , 2450.8904, 2450.8882],
[2450.9658, 2450.9355, 2450.9958, 2450.9653, 2450.7627, 2450.686 ,
2450.689 , 2450.689 , 2450.6824, 2450.6914, 2451.0054, 2450.9502,
2450.9612, 2450.9336, 2450.9136, 2450.9077],
[2450.982 , 2450.988 , 2450.9907, 2450.9985, 2450.999 , 2450.9514,
2450.9734, 2450.9438, 2450.9673, 2451.0188, 2451.0056, 2450.9568,
2450.982 , 2450.9858, 2450.9749, 2450.9958]], dtype=float32), si_unit='ms')},
'loss_history': [0.15260642766952515,
0.1450989693403244,
0.13821451365947723],
'cached': False}],
'metadata': {'config': {'seed': 3, 'group': 'treated'}},
'study_dir': PosixPath('/tmp/mrax-notebook-smoke/tmp/analysis_toolbox_demo/inputs/treated_02')}]
ROI statistics for parameter maps¶
Load one subject's manifest and extract ROI statistics from the fitted maps.
[3]:
manifest = summaries[0]["manifest_path"]
data = load_study_results(manifest)
exp = data["experiments"]["t1_ir"]
maps = exp["fitted_maps"]
mr_image = exp["mr_image"]
mask = np.zeros(mr_image.shape[-2:], dtype=bool)
mask[4:12, 4:12] = True
roi = ROI("center", mask)
rows = collect_roi_stats(maps, [roi], stats=("mean", "variance"))
rows
[3]:
[{'map': 'amplitude',
'roi': 'center',
'stat': 'mean',
'value': 0.7074053883552551,
'unit': '1'},
{'map': 'amplitude',
'roi': 'center',
'stat': 'variance',
'value': 0.0008956128731369972,
'unit': '1'},
{'map': 't1',
'roi': 'center',
'stat': 'mean',
'value': 2452.32373046875,
'unit': 'ms'},
{'map': 't1',
'roi': 'center',
'stat': 'variance',
'value': 137.02313232421875,
'unit': 'ms'}]
ROI timecourse¶
Reduce the ROI in the raw image stack to a timecourse.
[4]:
timecourse = extract_timecourse(mr_image, roi, stat="mean")
ti = exp["observables"].get("TI")
ti_vals = np.asarray(ti.values) if ti is not None else np.arange(timecourse.shape[0])
fig, ax = plt.subplots(figsize=(4, 3))
ax.plot(ti_vals, timecourse, marker="o")
ax.set_xlabel("TI (ms)")
ax.set_ylabel("ROI mean signal")
ax.set_title("ROI timecourse")
plt.show()
Timecourse plotting and animation¶
The arrays returned by MRax analysis helpers can be plotted directly with matplotlib.
[5]:
from matplotlib.animation import FuncAnimation, PillowWriter
from mrax.analysis.timecourse_processing import mean_timecourses_by_label, nan_gaussian_filter, apply_baseline
def plot_timecourses(image_series, label_mask, times, *, dilution=None, baseline_frames=50, smooth_sigma=2.0, labels=None, infusion_times=None, time_scale=60.0, time_unit="min", save_path=None):
series = np.asarray(image_series, dtype=float)
times_arr = np.asarray(times, dtype=float)
raw_timecourses, label_values = mean_timecourses_by_label(
series,
label_mask,
baseline_frames=0,
smooth_sigma=smooth_sigma,
dilution=dilution,
)
timecourses = raw_timecourses.copy()
if baseline_frames > 0:
for idx in range(timecourses.shape[1]):
timecourses[:, idx] -= np.nanmean(timecourses[:baseline_frames, idx])
fig, ax = plt.subplots(figsize=(7.2, 4.2))
for infusion_time in infusion_times or []:
ax.axvline(x=infusion_time, color="gray", linestyle="--", linewidth=1)
labels = labels or {label: str(label) for label in label_values}
for idx, label in enumerate(label_values):
ax.plot(times_arr / time_scale, raw_timecourses[:, idx], label=labels.get(label, str(label)), linewidth=2)
ax.set_xlabel(f"Time ({time_unit})")
ax.set_ylabel("Parameter Value")
ax.legend(loc="upper right")
if save_path:
fig.savefig(save_path, dpi=300, bbox_inches="tight")
plt.close(fig)
return timecourses
def plot_mean_timecourses(timecourses, label, times, *, groups=None, infusion_times=None, vmin=None, vmax=None, label_index=0, time_scale=60.0, time_unit="min"):
data = np.asarray(timecourses, dtype=float)
times_arr = np.asarray(times, dtype=float)
if data.ndim == 3 and data.shape[1] == times_arr.size:
data = data[..., label_index][:, None, :]
elif data.ndim == 2 and data.shape[0] == times_arr.size:
data = data[:, label_index][None, None, :]
group_names = list(groups) if groups is not None else [f"Group {i+1}" for i in range(data.shape[0])]
fig, ax = plt.subplots(figsize=(7.2, 4.2))
for infusion_time in infusion_times or []:
ax.axvline(x=infusion_time, color="gray", linestyle="--", linewidth=1)
for group_idx, group_name in enumerate(group_names):
group_data = data[group_idx]
mean_tc = np.nanmean(group_data, axis=0)
sem_tc = np.nanstd(group_data, axis=0) / np.sqrt(max(1, group_data.shape[0]))
line, = ax.plot(times_arr / time_scale, mean_tc, lw=2, label=group_name)
ax.fill_between(times_arr / time_scale, mean_tc - sem_tc, mean_tc + sem_tc, color=line.get_color(), alpha=0.25)
ax.set_xlabel(f"Time ({time_unit})")
ax.set_ylabel(label)
if vmin is not None or vmax is not None:
ax.set_ylim(vmin, vmax)
ax.legend(frameon=False, loc="upper right")
return fig
def map_animation(image_series, reference, times, save_path, *, dilution=None, vmin=0.0, vmax=0.0005, infusion_times=None, baseline_frames=5, smooth_sigma=1.0, fps=30, dpi=300):
series = np.asarray(image_series, dtype=float)
if smooth_sigma and smooth_sigma > 0:
series = nan_gaussian_filter(series, sigma=smooth_sigma)
if dilution is not None:
dil = apply_baseline(np.asarray(dilution, dtype=float), baseline_frames=baseline_frames, mode="divide", axis=0)
with np.errstate(invalid="ignore", divide="ignore"):
series = series / np.clip(dil, 1e-2, None)
times_arr = np.asarray(times, dtype=float)
baseline = np.nanmean(series[:baseline_frames], axis=0)
fig, ax = plt.subplots(figsize=(5, 5))
ax.imshow(reference, cmap="gray")
im = ax.imshow(series[0] - baseline, vmin=vmin, vmax=vmax, cmap="jet")
ax.axis("off")
plt.colorbar(im, ax=ax)
title = ax.set_title(f"t={times_arr[0]:.2f}")
def update(frame):
im.set_array(series[frame] - baseline)
title.set_text(f"t={times_arr[frame]:.2f}")
return [im, title]
anim = FuncAnimation(fig, update, frames=series.shape[0], blit=True)
anim.save(save_path, writer=PillowWriter(fps=fps), dpi=dpi)
plt.close(fig)
label_mask = np.zeros(mr_image.shape[-2:], dtype=int)
label_mask[4:12, 4:12] = 1
timecourses = plot_timecourses(
mr_image,
label_mask,
times=ti_vals * 1e-3,
infusion_times=[5],
)
plot_mean_timecourses(
timecourses[None, ...],
label="Signal",
times=ti_vals * 1e-3,
groups=["control"],
label_index=0,
)
[5]:
[6]:
animation_path = outputs_root / "roi_animation.gif"
map_animation(
mr_image,
reference=mr_image[0],
times=ti_vals * 1e-3,
save_path=str(animation_path),
)
animation_path
[6]:
PosixPath('/tmp/mrax-notebook-smoke/tmp/analysis_toolbox_demo/outputs/roi_animation.gif')
Group summaries and comparisons¶
Use the batch output root to compare groups. Members can be study folder names
(inside outputs_root) or explicit manifest paths.
[7]:
groups = {
"control": ["control_01", "control_02"],
"treated": ["treated_01", "treated_02"],
}
results = analyze_groups(
groups,
output_root=outputs_root,
experiment_name="t1_ir",
rois=[roi],
map_names=["t1"],
stats=("mean",),
p_adjust="fdr_bh",
)
results["group_summary"]
[7]:
[{'group': 'control',
'experiment': 't1_ir',
'map': 't1',
'roi': 'center',
'stat': 'mean',
'count': 2.0,
'nan_count': 0.0,
'mean': 2452.281494140625,
'variance': 0.003567814826965332,
'std': 0.05973118805921519,
'sem': 0.04223632812499999,
'median': 2452.281494140625,
'min': 2452.2392578125,
'max': 2452.32373046875,
'p25': 2452.2603759765625,
'p75': 2452.3026123046875,
'unit': 'ms'},
{'group': 'treated',
'experiment': 't1_ir',
'map': 't1',
'roi': 'center',
'stat': 'mean',
'count': 2.0,
'nan_count': 0.0,
'mean': 2454.6890869140625,
'variance': 0.08044984936714172,
'std': 0.28363682653552186,
'sem': 0.20056152343749997,
'median': 2454.6890869140625,
'min': 2454.488525390625,
'max': 2454.8896484375,
'p25': 2454.5888061523438,
'p75': 2454.7893676757812,
'unit': 'ms'}]
[8]:
results["comparisons"]
[8]:
[{'experiment': 't1_ir',
'map': 't1',
'roi': 'center',
'stat': 'mean',
'group_a': 'control',
'group_b': 'treated',
'n_a': 2.0,
'n_b': 2.0,
'mean_a': 2452.281494140625,
'mean_b': 2454.68896484375,
'mean_diff': -2.407470703125,
't_stat': -11.746614794850906,
't_p': 0.04431433472445087,
'effect_size_d': -11.746614794850906,
'effect_size_g': -6.712351311343374,
'np_test': 'mannwhitney',
'np_stat': 0.0,
'np_p': 0.3333333333333333,
'unit': 'ms',
't_p_fdr_bh': 0.04431433472445087}]
Plot group distributions and significance¶
Visualize per-subject distributions and group summaries with significance markers.
[9]:
def _grouped_values(rows, *, experiment, map_name, roi, stat):
grouped = {}
for row in rows:
if row.get("experiment") == experiment and row.get("map") == map_name and row.get("roi") == roi and row.get("stat") == stat:
grouped.setdefault(str(row.get("group")), []).append(float(row.get("value", np.nan)))
return grouped
def _significance_label(p_value):
if p_value is None or not np.isfinite(p_value):
return "n/a"
if p_value <= 0.001:
return "***"
if p_value <= 0.01:
return "**"
if p_value <= 0.05:
return "*"
return "n.s."
def plot_group_distributions(subject_rows, *, experiment, map_name, roi, stat, comparisons=None, kind="box"):
grouped = _grouped_values(subject_rows, experiment=experiment, map_name=map_name, roi=roi, stat=stat)
order = sorted(grouped)
values = [grouped[name] for name in order]
fig, ax = plt.subplots(figsize=(5.2, 3.6))
positions = np.arange(len(order))
if kind == "violin":
ax.violinplot(values, positions=positions, showmedians=True)
else:
ax.boxplot(values, positions=positions, widths=0.6, patch_artist=True)
rng = np.random.default_rng(0)
for idx, group_vals in enumerate(values):
ax.scatter(np.full(len(group_vals), positions[idx]) + rng.normal(0, 0.04, len(group_vals)), group_vals, s=16, color="#2f2f2f", alpha=0.65)
ax.set_xticks(positions)
ax.set_xticklabels(order)
ax.set_ylabel(stat)
ax.set_title(f"{experiment} - {map_name} - {roi}")
return fig
def plot_group_summary(summary_rows, *, experiment, map_name, roi, stat, comparisons=None, value_key="mean", error_key="sem"):
rows = [row for row in summary_rows if row.get("experiment") == experiment and row.get("map") == map_name and row.get("roi") == roi and row.get("stat") == stat]
order = sorted(str(row.get("group")) for row in rows)
by_group = {str(row.get("group")): row for row in rows}
means = [float(by_group[group].get(value_key, np.nan)) for group in order]
errors = [float(by_group[group].get(error_key, np.nan)) for group in order]
fig, ax = plt.subplots(figsize=(5.2, 3.6))
positions = np.arange(len(order))
ax.bar(positions, means, yerr=errors, capsize=4, color="#88aadd", alpha=0.8)
ax.set_xticks(positions)
ax.set_xticklabels(order)
ax.set_ylabel(f"{value_key} ({stat})")
ax.set_title(f"{experiment} - {map_name} - {roi}")
return fig
fig = plot_group_distributions(
results["subject_stats"],
comparisons=results["comparisons"],
experiment="t1_ir",
map_name="t1",
roi="center",
stat="mean",
kind="box",
)
plt.show()
[10]:
fig = plot_group_summary(
results["group_summary"],
comparisons=results["comparisons"],
experiment="t1_ir",
map_name="t1",
roi="center",
stat="mean",
)
plt.show()