1# -*- coding: utf-8 -*- 2"""Functions related to the documentation. 3 4docdict contains the standard documentation entries 5used across Nilearn. 6 7source: Eric Larson and MNE-python team. 8https://github.com/mne-tools/mne-python/blob/main/mne/utils/docs.py 9""" 10 11import sys 12 13 14################################### 15# Standard documentation entries 16# 17docdict = dict() 18 19NILEARN_LINKS = {"landing_page": "http://nilearn.github.io"} 20NILEARN_LINKS["input_output"] = ( 21 "{}/manipulating_images/input_output.html".format( 22 NILEARN_LINKS["landing_page"]) 23) 24 25# Verbose 26verbose = """ 27verbose : :obj:`int`, optional 28 Verbosity level (0 means no message). 29 Default={}.""" 30docdict['verbose'] = verbose.format(1) 31docdict['verbose0'] = verbose.format(0) 32 33# Resume 34docdict['resume'] = """ 35resume : :obj:`bool`, optional 36 Whether to resume download of a partly-downloaded file. 37 Default=True.""" 38 39# Data_dir 40docdict['data_dir'] = """ 41data_dir : :obj:`pathlib.Path` or :obj:`str`, optional 42 Path where data should be downloaded. By default, 43 files are downloaded in home directory.""" 44 45# URL 46docdict['url'] = """ 47url : :obj:`str`, optional 48 URL of file to download. 49 Override download URL. Used for test only (or if you 50 setup a mirror of the data). 51 Default=None.""" 52 53# Smoothing_fwhm 54docdict['smoothing_fwhm'] = """ 55smoothing_fwhm : :obj:`float`, optional. 56 If ``smoothing_fwhm`` is not ``None``, it gives 57 the full-width at half maximum in millimeters 58 of the spatial smoothing to apply to the signal.""" 59 60# Standardize 61standardize = """ 62standardize : :obj:`bool`, optional. 63 If ``standardize`` is True, the data are centered and normed: 64 their mean is put to 0 and their variance is put to 1 in the 65 time dimension. 66 Default={}.""" 67docdict['standardize'] = standardize.format('True') 68docdict['standardize_false'] = standardize.format('False') 69 70# detrend 71docdict['detrend'] = """ 72detrend : :obj:`bool`, optional 73 Whether to detrend signals or not.""" 74 75# Target_affine 76docdict['target_affine'] = """ 77target_affine : :class:`numpy.ndarray`, optional. 78 If specified, the image is resampled corresponding to this new affine. 79 ``target_affine`` can be a 3x3 or a 4x4 matrix. 80 Default=None.""" 81 82# Target_shape 83docdict['target_shape'] = """ 84target_shape : :obj:`tuple` or :obj:`list`, optional. 85 If specified, the image will be resized to match this new shape. 86 ``len(target_shape)`` must be equal to 3. 87 88 .. note:: 89 If ``target_shape`` is specified, a ``target_affine`` of shape 90 ``(4, 4)`` must also be given. 91 92 Default=None.""" 93 94# Low_pass 95docdict['low_pass'] = """ 96low_pass : :obj:`float` or None, optional 97 Low cutoff frequency in Hertz. 98 If None, no low-pass filtering will be performed. 99 Default=None.""" 100 101# High pass 102docdict['high_pass'] = """ 103high_pass : :obj:`float`, optional 104 High cutoff frequency in Hertz. 105 Default=None.""" 106 107# t_r 108docdict['t_r'] = """ 109t_r : :obj:`float` or None, optional 110 Repetition time, in seconds (sampling period). 111 Set to ``None`` if not provided. 112 Default=None.""" 113 114# mask_img 115docdict['mask_img'] = """ 116mask_img : Niimg-like object 117 Object used for masking the data.""" 118 119# Memory 120docdict['memory'] = """ 121memory : instance of :class:`joblib.Memory` or :obj:`str` 122 Used to cache the masking process. 123 By default, no caching is done. If a :obj:`str` is given, it is the 124 path to the caching directory.""" 125 126# n_parcels 127docdict['n_parcels'] = """ 128n_parcels : :obj:`int`, optional 129 Number of parcels to divide the data into. 130 Default=50.""" 131 132# random_state 133docdict['random_state'] = """ 134random_state : :obj:`int` or RandomState, optional 135 Pseudo-random number generator state used for random sampling.""" 136 137# Memory_level 138memory_level = """ 139memory_level : :obj:`int`, optional. 140 Rough estimator of the amount of memory used by caching. Higher value 141 means more memory for caching. 142 Default={}.""" 143docdict['memory_level'] = memory_level.format(0) 144docdict['memory_level1'] = memory_level.format(1) 145 146# n_jobs 147n_jobs = """ 148n_jobs : :obj:`int`, optional. 149 The number of CPUs to use to do the computation. -1 means 'all CPUs'. 150 Default={}.""" 151docdict['n_jobs'] = n_jobs.format("1") 152docdict['n_jobs_all'] = n_jobs.format("-1") 153 154# img 155docdict['img'] = """ 156img : Niimg-like object 157 See `input-output <%(input_output)s>`_. 158""" % NILEARN_LINKS 159 160# imgs 161docdict['imgs'] = """ 162imgs : :obj:`list` of Niimg-like objects 163 See `input-output <%(input_output)s>`_. 164""" % NILEARN_LINKS 165 166# cut_coords 167docdict['cut_coords'] = """ 168cut_coords : None, a :obj:`tuple` of :obj:`float`, or :obj:`int`, optional 169 The MNI coordinates of the point where the cut is performed. 170 171 - If ``display_mode`` is 'ortho' or 'tiled', this should 172 be a 3-tuple: ``(x, y, z)`` 173 - For ``display_mode == 'x'``, 'y', or 'z', then these are 174 the coordinates of each cut in the corresponding direction. 175 - If ``None`` is given, the cuts are calculated automatically. 176 - If ``display_mode`` is 'mosaic', and the number of cuts is the same 177 for all directions, ``cut_coords`` can be specified as an integer. 178 It can also be a length 3 tuple specifying the number of cuts for 179 every direction if these are different. 180 181 .. note:: 182 183 If ``display_mode`` is 'x', 'y' or 'z', ``cut_coords`` can be 184 an integer, in which case it specifies the number of 185 cuts to perform. 186 187""" 188 189# output_file 190docdict['output_file'] = """ 191output_file : :obj:`str`, or None, optional 192 The name of an image file to export the plot to. Valid extensions 193 are .png, .pdf, .svg. If ``output_file`` is not None, the plot 194 is saved to a file, and the display is closed.""" 195 196# extractor / extract_type 197docdict['extractor'] = """ 198extractor : {'local_regions', 'connected_components'}, optional 199 This option can take two values: 200 201 - 'connected_components': each component/region in the image is 202 extracted automatically by labelling each region based upon the 203 presence of unique features in their respective regions. 204 205 - 'local_regions': each component/region is extracted based on 206 their maximum peak value to define a seed marker and then using 207 random walker segmentation algorithm on these markers for region 208 separation. 209 210 Default='local_regions'.""" 211docdict['extract_type'] = docdict['extractor'] 212 213# display_mode 214docdict['display_mode'] = """ 215display_mode : {'ortho', 'tiled', 'mosaic','x',\ 216'y', 'z', 'yx', 'xz', 'yz'}, optional 217 Choose the direction of the cuts: 218 219 - 'x': sagittal 220 - 'y': coronal 221 - 'z': axial 222 - 'ortho': three cuts are performed in orthogonal 223 directions 224 - 'tiled': three cuts are performed and arranged 225 in a 2x2 grid 226 - 'mosaic': three cuts are performed along 227 multiple rows and columns 228 229 Default='ortho'.""" 230 231# figure 232docdict['figure'] = """ 233figure : :obj:`int`, or :class:`matplotlib.figure.Figure`, or None, optional 234 Matplotlib figure used or its number. If ``None`` is given, a 235 new figure is created.""" 236 237# axes 238docdict['axes'] = """ 239axes : :class:`matplotlib.axes.Axes`, or 4 tuple\ 240of :obj:`float`: (xmin, ymin, width, height), optional 241 The axes, or the coordinates, in matplotlib figure 242 space, of the axes used to display the plot. 243 If ``None``, the complete figure is used.""" 244 245# title 246docdict['title'] = """ 247title : :obj:`str`, or None, optional 248 The title displayed on the figure. 249 Default=None.""" 250 251# threshold 252docdict['threshold'] = """ 253threshold : a number, None, or 'auto', optional 254 If ``None`` is given, the image is not thresholded. 255 If a number is given, it is used to threshold the image: 256 values below the threshold (in absolute value) are plotted 257 as transparent. If 'auto' is given, the threshold is determined 258 magically by analysis of the image. 259""" 260 261# annotate 262docdict['annotate'] = """ 263annotate : :obj:`bool`, optional 264 If ``annotate`` is ``True``, positions and left/right annotation 265 are added to the plot. Default=True.""" 266 267# draw_cross 268docdict['draw_cross'] = """ 269draw_cross : :obj:`bool`, optional 270 If ``draw_cross`` is ``True``, a cross is drawn on the plot to indicate 271 the cut position. Default=True.""" 272 273# black_bg 274docdict['black_bg'] = """ 275black_bg : :obj:`bool`, or 'auto', optional 276 If ``True``, the background of the image is set to be black. 277 If you wish to save figures with a black background, you 278 will need to pass facecolor='k', edgecolor='k' 279 to :func:`matplotlib.pyplot.savefig`.""" 280 281# colorbar 282docdict['colorbar'] = """ 283colorbar : :obj:`bool`, optional 284 If ``True``, display a colorbar on the right of the plots.""" 285 286# symmetric_cbar 287docdict['symmetric_cbar'] = """ 288symmetric_cbar : :obj:`bool`, or 'auto', optional 289 Specifies whether the colorbar should range from ``-vmax`` to ``vmax`` 290 or from ``vmin`` to ``vmax``. Setting to 'auto' will select the latter 291 if the range of the whole image is either positive or negative. 292 293 .. note:: 294 295 The colormap will always range from ``-vmax`` to ``vmax``. 296 297""" 298 299# cbar_tick_format 300docdict['cbar_tick_format'] = """ 301cbar_tick_format : :obj:`str`, optional 302 Controls how to format the tick labels of the colorbar. 303 Ex: use "%%.2g" to display using scientific notation.""" 304 305# bg_img 306docdict['bg_img'] = """ 307bg_img : Niimg-like object, optional 308 See `input_output <%(input_output)s>`_. 309 The background image to plot on top of. 310""" % NILEARN_LINKS 311 312# vmin 313docdict['vmin'] = """ 314vmin : :obj:`float`, optional 315 Lower bound of the colormap. If ``None``, the min of the image is used. 316 Passed to :func:`matplotlib.pyplot.imshow`. 317""" 318 319# vmax 320docdict['vmax'] = """ 321vmax : :obj:`float`, optional 322 Upper bound of the colormap. If ``None``, the max of the image is used. 323 Passed to :func:`matplotlib.pyplot.imshow`. 324""" 325 326# bg_vmin 327docdict['bg_vmin'] = """ 328bg_vmin : :obj:`float`, optional 329 vmin for ``bg_img``.""" 330 331# bg_vmax 332docdict['bg_vmax'] = """ 333bg_vmin : :obj:`float`, optional 334 vmax for ``bg_img``.""" 335 336# resampling_interpolation 337docdict['resampling_interpolation'] = """ 338resampling_interpolation : :obj:`str`, optional 339 Interpolation to use when resampling the image to 340 the destination space. Can be: 341 342 - "continuous": use 3rd-order spline interpolation 343 - "nearest": use nearest-neighbor mapping. 344 345 .. note:: 346 347 "nearest" is faster but can be noisier in some cases. 348 349""" 350 351# cmap 352docdict['cmap'] = """ 353cmap : :class:`matplotlib.colors.Colormap`, or :obj:`str`, optional 354 The colormap to use. Either a string which is a name of 355 a matplotlib colormap, or a matplotlib colormap object.""" 356 357# Dimming factor 358docdict['dim'] = """ 359dim : :obj:`float`, or 'auto', optional 360 Dimming factor applied to background image. By default, automatic 361 heuristics are applied based upon the background image intensity. 362 Accepted float values, where a typical span is between -2 and 2 363 (-2 = increase contrast; 2 = decrease contrast), but larger values 364 can be used for a more pronounced effect. 0 means no dimming.""" 365 366# avg_method 367docdict['avg_method'] = """ 368avg_method : {'mean', 'median', 'min', 'max', custom function}, optional 369 How to average vertex values to derive the face value: 370 371 - ``mean``: results in smooth boundaries 372 - ``median``: results in sharp boundaries 373 - ``min`` or ``max``: for sparse matrices 374 - ``custom function``: You can also pass a custom function 375 which will be executed though :func:`numpy.apply_along_axis`. 376 Here is an example of a custom function: 377 378 .. code-block:: python 379 380 def custom_function(vertices): 381 return vertices[0] * vertices[1] * vertices[2] 382 383""" 384 385# hemi 386docdict['hemi'] = """ 387hemi : {'left', 'right'}, optional 388 Hemisphere to display. Default='left'.""" 389 390# hemispheres 391docdict['hemispheres'] = """ 392hemispheres : list of :obj:`str`, optional 393 Hemispheres to display. Default=['left', 'right'].""" 394 395# view 396docdict['view'] = """ 397view : {'lateral', 'medial', 'dorsal', 'ventral',\ 398 'anterior', 'posterior'}, optional 399 View of the surface that is rendered. 400 Default='lateral'. 401""" 402 403# bg_on_data 404docdict['bg_on_data'] = """ 405bg_on_data : :obj:`bool`, optional 406 If ``True``, and a ``bg_map`` is specified, 407 the ``surf_data`` data is multiplied by the background 408 image, so that e.g. sulcal depth is visible beneath 409 the ``surf_data``. 410 411 .. note:: 412 This non-uniformly changes the surf_data values according 413 to e.g the sulcal depth. 414 415""" 416 417# darkness 418docdict['darkness'] = """ 419darkness : :obj:`float` between 0 and 1, optional 420 Specifying the darkness of the background image: 421 422 - '1' indicates that the original values of the background are used 423 - '.5' indicates that the background values are reduced by half 424 before being applied. 425 426""" 427 428# linewidth 429docdict['linewidths'] = """ 430linewidths : :obj:`float`, optional 431 Set the boundary thickness of the contours. 432 Only reflects when ``view_type=contours``.""" 433 434# fsaverage options 435docdict['fsaverage_options'] = """ 436 437 - 'fsaverage3': the low-resolution fsaverage3 mesh (642 nodes) 438 - 'fsaverage4': the low-resolution fsaverage4 mesh (2562 nodes) 439 - 'fsaverage5': the low-resolution fsaverage5 mesh (10242 nodes) 440 - 'fsaverage5_sphere': the low-resolution fsaverage5 spheres 441 442 .. deprecated:: 0.8.0 443 This option has been deprecated and will be removed in v0.9.0. 444 fsaverage5 sphere coordinates can now be accessed through 445 attributes sphere_{left, right} using mesh='fsaverage5' 446 447 - 'fsaverage6': the medium-resolution fsaverage6 mesh (40962 nodes) 448 - 'fsaverage7': same as 'fsaverage' 449 - 'fsaverage': the high-resolution fsaverage mesh (163842 nodes) 450 451 .. note:: 452 The high-resolution fsaverage will result in more computation 453 time and memory usage 454 455""" 456 457# Classifiers 458base_url = "https://scikit-learn.org/stable/modules/generated/sklearn" 459svc = "Linear support vector classifier" 460logistic = "Logistic regression" 461rc = "Ridge classifier" 462dc = "Dummy classifier with stratified strategy" 463SKLEARN_LINKS = { 464 'svc': f"{base_url}.svm.SVC.html", 465 'logistic': f"{base_url}.linear_model.LogisticRegression.html", 466 'ridge_classifier': f"{base_url}.linear_model.RidgeClassifierCV.html", 467 'dummy_classifier': f"{base_url}.dummy.DummyClassifier.html", 468 'ridge': f"{base_url}.linear_model.RidgeCV.html", 469 'svr': f"{base_url}.svm.SVR.html", 470 'dummy_regressor': f"{base_url}.dummy.DummyRegressor.html", 471} 472 473docdict['classifier_options'] = f""" 474 475 - `svc`: `{svc} <%(svc)s>`_ with L2 penalty. 476 .. code-block:: python 477 478 svc = LinearSVC(penalty='l2', 479 max_iter=1e4) 480 481 - `svc_l2`: `{svc} <%(svc)s>`_ with L2 penalty. 482 .. note:: 483 Same as option `svc`. 484 485 - `svc_l1`: `{svc} <%(svc)s>`_ with L1 penalty. 486 .. code-block:: python 487 488 svc_l1 = LinearSVC(penalty='l1', 489 dual=False, 490 max_iter=1e4) 491 492 - `logistic`: `{logistic} <%(logistic)s>`_ with L2 penalty. 493 .. code-block:: python 494 495 logistic = LogisticRegression(penalty='l2', 496 solver='liblinear') 497 498 - `logistic_l1`: `{logistic} <%(logistic)s>`_ with L1 penalty. 499 .. code-block:: python 500 501 logistic_l1 = LogisticRegression(penalty='l1', 502 solver='liblinear') 503 504 - `logistic_l2`: `{logistic} <%(logistic)s>`_ with L2 penalty 505 .. note:: 506 Same as option `logistic`. 507 508 - `ridge_classifier`: `{rc} <%(ridge_classifier)s>`_. 509 .. code-block:: python 510 511 ridge_classifier = RidgeClassifierCV() 512 513 - `dummy_classifier`: `{dc} <%(dummy_classifier)s>`_. 514 .. code-block:: python 515 516 dummy = DummyClassifier(strategy='stratified', 517 random_state=0) 518 519""" % SKLEARN_LINKS 520 521docdict['regressor_options'] = """ 522 523 - `ridge`: `Ridge regression <%(ridge)s>`_. 524 .. code-block:: python 525 526 ridge = RidgeCV() 527 528 - `ridge_regressor`: `Ridge regression <%(ridge)s>`_. 529 .. note:: 530 Same option as `ridge`. 531 532 - `svr`: `Support vector regression <%(svr)s>`_. 533 .. code-block:: python 534 535 svr = SVR(kernel='linear', 536 max_iter=1e4) 537 538 - `dummy_regressor`: `Dummy regressor <%(dummy_regressor)s>`_. 539 .. code-block:: python 540 541 dummy = DummyRegressor(strategy='mean') 542 543""" % SKLEARN_LINKS 544 545# mask_strategy 546docdict["mask_strategy"] = """ 547mask_strategy : {'background', 'epi', 'whole-brain-template',\ 548'gm-template', 'wm-template'}, optional 549 The strategy used to compute the mask: 550 551 - 'background': Use this option if your images present 552 a clear homogeneous background. 553 - 'epi': Use this option if your images are raw EPI images 554 - 'whole-brain-template': This will extract the whole-brain 555 part of your data by resampling the MNI152 brain mask for 556 your data's field of view. 557 558 .. note:: 559 This option is equivalent to the previous 'template' option 560 which is now deprecated. 561 562 - 'gm-template': This will extract the gray matter part of your 563 data by resampling the corresponding MNI152 template for your 564 data's field of view. 565 566 .. versionadded:: 0.8.1 567 568 - 'wm-template': This will extract the white matter part of your 569 data by resampling the corresponding MNI152 template for your 570 data's field of view. 571 572 .. versionadded:: 0.8.1 573 574""" 575 576docdict_indented = {} 577 578 579def _indentcount_lines(lines): 580 """Minimum indent for all lines in line list. 581 582 >>> lines = [' one', ' two', ' three'] 583 >>> _indentcount_lines(lines) 584 1 585 >>> lines = [] 586 >>> _indentcount_lines(lines) 587 0 588 >>> lines = [' one'] 589 >>> _indentcount_lines(lines) 590 1 591 >>> _indentcount_lines([' ']) 592 0 593 594 """ 595 indentno = sys.maxsize 596 for line in lines: 597 stripped = line.lstrip() 598 if stripped: 599 indentno = min(indentno, len(line) - len(stripped)) 600 if indentno == sys.maxsize: 601 return 0 602 return indentno 603 604 605def fill_doc(f): 606 """Fill a docstring with docdict entries. 607 608 Parameters 609 ---------- 610 f : callable 611 The function to fill the docstring of. Will be modified in place. 612 613 Returns 614 ------- 615 f : callable 616 The function, potentially with an updated ``__doc__``. 617 618 """ 619 docstring = f.__doc__ 620 if not docstring: 621 return f 622 lines = docstring.splitlines() 623 # Find the minimum indent of the main docstring, after first line 624 if len(lines) < 2: 625 icount = 0 626 else: 627 icount = _indentcount_lines(lines[1:]) 628 # Insert this indent to dictionary docstrings 629 try: 630 indented = docdict_indented[icount] 631 except KeyError: 632 indent = ' ' * icount 633 docdict_indented[icount] = indented = {} 634 for name, dstr in docdict.items(): 635 lines = dstr.splitlines() 636 try: 637 newlines = [lines[0]] 638 for line in lines[1:]: 639 newlines.append(indent + line) 640 indented[name] = '\n'.join(newlines) 641 except IndexError: 642 indented[name] = dstr 643 try: 644 f.__doc__ = docstring % indented 645 except (TypeError, ValueError, KeyError) as exp: 646 funcname = f.__name__ 647 funcname = docstring.split('\n')[0] if funcname is None else funcname 648 raise RuntimeError('Error documenting %s:\n%s' 649 % (funcname, str(exp))) 650 return f 651